Related
I am plotting an Indian map using plotly and geojson file. Now what I want to do is show static values on the Indian States. Currently those values are visible on hover, I want the values to be seen all the time.
This my code :
import pandas as pd
import plotly.graph_objects as go
df = data_state1
fig = go.Figure(data=go.Choropleth(
geojson="https://gist.githubusercontent.com/jbrobst/56c13bbbf9d97d187fea01ca62ea5112/raw/e388c4cae20aa53cb5090210a42ebb9b765c0a36/india_states.geojson",
featureidkey='properties.ST_NM',
locationmode='geojson-id',
locations=df['ST_NM'].str.title(), # To make lower case to CamelCase
z=df['odval']/df['count'],
text= df['ST_NM'].str.title(),
autocolorscale=False,
colorscale='Reds',
marker_line_color='darkgreen',
colorbar=dict(
title={'text': "Amount"},
thickness=35,
len=1.0,
bgcolor='rgba(255,255,255,0.6)',
xanchor='right',
x=0.0,
yanchor='bottom',
y=0.0
),
))
fig.update_geos(
visible=True,
projection=dict(
type='conic conformal',
parallels=[12.472944444, 35.172805555556],
rotation={'lat': 24, 'lon': 80}
),
lonaxis={'range': [68, 98]},
lataxis={'range': [6, 38]}
)
fig.update_layout(
title=dict(
text="Average Overdue Amount over Total cases ",
xanchor='center',
x=0.5,
yref='paper',
yanchor='bottom',
y=0.9,
pad={'b': 0}
),
margin={'r': 0, 't': 0, 'l': 0, 'b': 0},
height=850,
width=750
)
fig.show()
I also tried with geopandas, on that plot, i was able to plot map with colours on the basis of values, but did not find a way to show state names and values.
Code for geopandas is :
fig, ax = plt.subplots(1, figsize=(10, 10))
ax.axis('off')
ax.set_title('ODVal/Cases distribution',
fontdict={'fontsize': '15', 'fontweight' : '3'})
merged.plot(column='ratio_od_cases',cmap='Reds', linewidth=0.8, ax=ax, edgecolor='0', legend=True)
plt.text(,merged['State_Name'])
I think the easiest way to add text on the map is to use text mode in go.Scattergeo() and specify the latitude and longitude. From the geojson data used, geopandas is used to calculate the center of the state for the text display.
import pandas as pd
import numpy as np
import plotly.graph_objects as go
from urllib import request
import json
url = "https://gist.githubusercontent.com/jbrobst/56c13bbbf9d97d187fea01ca62ea5112/raw/e388c4cae20aa53cb5090210a42ebb9b765c0a36/india_states.geojson"
with request.urlopen(url) as f:
geo_india = json.load(f)
import geopandas as gpd
df = gpd.read_file(url)
df["lon"] = df["geometry"].centroid.x
df["lat"] = df["geometry"].centroid.y
df['value'] = np.random.randint(5,50,36)
fig = go.Figure(data=go.Choropleth(
geojson=geo_india,
featureidkey='properties.ST_NM',
#locationmode='geojson-id',
locations=df['ST_NM'].str.title(), # To make lower case to CamelCase
z=df['value'],
text= df['ST_NM'].str.title(),
autocolorscale=False,
colorscale='Reds',
marker_line_color='darkgreen',
colorbar=dict(
title={'text': "Amount"},
thickness=35,
len=1.0,
bgcolor='rgba(255,255,255,0.6)',
xanchor='right',
x=0.0,
yanchor='bottom',
y=0.0
),
))
fig.update_geos(
visible=True,
projection=dict(
type='conic conformal',
parallels=[12.472944444, 35.172805555556],
rotation={'lat': 24, 'lon': 80}
),
lonaxis={'range': [68, 98]},
lataxis={'range': [6, 38]}
)
fig.add_trace(go.Scattergeo(
lon=df['lon'],
lat=df['lat'],
mode='text',
#text=df['ST_NM'].str.title(),
text=['{}<br>{}'.format(k,v) for k,v in zip(df['ST_NM'].str.title(), df['value'])],
textfont={'color': 'Green'},
name='',
))
fig.update_layout(
title=dict(
text="Average Overdue Amount over Total cases ",
xanchor='center',
x=0.5,
yref='paper',
yanchor='bottom',
y=0.9,
pad={'b': 0}
),
margin={'r': 0, 't': 0, 'l': 0, 'b': 0},
height=850,
width=750
)
fig.show()
code:
from plotly.offline import init_notebook_mode, iplot, iplot_mpl
def plot_train_test(train, test, date_split):
data = [Candlestick(x=train.index, open=train['open'], high=train['high'], low=train['low'], close=train['close'],name='train'),
Candlestick(x=test.index, open=test['open'], high=test['high'], low=test['low'], close=test['close'],name='test')
]
layout = {
'shapes': [
{'x0': date_split, 'x1': date_split, 'y0': 0, 'y1': 1, 'xref': 'x', 'yref': 'paper',
'line': {'color': 'rgb(0,0,0)', 'width': 1}}],
'annotations': [{'x': date_split, 'y': 1.0, 'xref': 'x', 'yref': 'paper', 'showarrow': False, 'xanchor': 'left','text': ' test data'},
{'x': date_split, 'y': 1.0, 'xref': 'x', 'yref': 'paper', 'showarrow': False, 'xanchor': 'right', 'text': 'train data '}] }
figure = Figure(data=data, layout=layout)
iplot(figure)
The above code is ok.But now I want to 'volume' in this candlestick chart
code:
from plotly.offline import init_notebook_mode, iplot, iplot_mpl
def plot_train_test(train, test, date_split):
data = [Candlestick(x=train.index, open=train['open'], high=train['high'], low=train['low'], close=train['close'],volume=train['volume'],name='train'),
Candlestick(x=test.index, open=test['open'], high=test['high'], low=test['low'],close=test['close'],volume=test['volume'],name='test')]
layout = {
'shapes': [
{'x0': date_split, 'x1': date_split, 'y0': 0, 'y1': 1, 'xref': 'x', 'yref': 'paper',
'line': {'color': 'rgb(0,0,0)', 'width': 1}}
],
'annotations': [
{'x': date_split, 'y': 1.0, 'xref': 'x', 'yref': 'paper', 'showarrow': False, 'xanchor': 'left',
'text': ' test data'},
{'x': date_split, 'y': 1.0, 'xref': 'x', 'yref': 'paper', 'showarrow': False, 'xanchor': 'right',
'text': 'train data '}
]
}
figure = Figure(data=data, layout=layout)
iplot(figure)
error:
ValueError: Invalid property specified for object of type
plotly.graph_objs.Candlestick: 'volume'
If you looking add smaller subplot of volume just below OHLC chart, you can use:
rows and cols to specify the grid for subplots.
shared_xaxes=True for same zoom and filtering
row_width=[0.2, 0.7] to change height ratio of charts. ie. smaller volume chart than OHLC
Plot:
import pandas as pd
import plotly.graph_objects as go
from plotly.subplots import make_subplots
# data
df = pd.read_csv('https://raw.githubusercontent.com/plotly/datasets/master/finance-charts-apple.csv')
# Create subplots and mention plot grid size
fig = make_subplots(rows=2, cols=1, shared_xaxes=True,
vertical_spacing=0.03, subplot_titles=('OHLC', 'Volume'),
row_width=[0.2, 0.7])
# Plot OHLC on 1st row
fig.add_trace(go.Candlestick(x=df["Date"], open=df["AAPL.Open"], high=df["AAPL.High"],
low=df["AAPL.Low"], close=df["AAPL.Close"], name="OHLC"),
row=1, col=1
)
# Bar trace for volumes on 2nd row without legend
fig.add_trace(go.Bar(x=df['Date'], y=df['AAPL.Volume'], showlegend=False), row=2, col=1)
# Do not show OHLC's rangeslider plot
fig.update(layout_xaxis_rangeslider_visible=False)
fig.show()
You haven't provided a complete code snippet with a data sample, so I'm going to have to suggest a solution that builds on an example here.
In any case, you're getting that error message simply because go.Candlestick does not have a Volume attribute. And it might not seem so at first, but you can easily set up go.Candlestick as an individual trace, and then include an individual go.Bar() trace for Volumes using:
fig = make_subplots(specs=[[{"secondary_y": True}]])
fig.add_traces(go.Candlestick(...), secondary_y=True)
fig.add_traces(go.Bar(...), secondary_y=False)
Plot:
Complete code:
import plotly.graph_objects as go
from plotly.subplots import make_subplots
import pandas as pd
# data
df = pd.read_csv('https://raw.githubusercontent.com/plotly/datasets/master/finance-charts-apple.csv')
# Create figure with secondary y-axis
fig = make_subplots(specs=[[{"secondary_y": True}]])
# include candlestick with rangeselector
fig.add_trace(go.Candlestick(x=df['Date'],
open=df['AAPL.Open'], high=df['AAPL.High'],
low=df['AAPL.Low'], close=df['AAPL.Close']),
secondary_y=True)
# include a go.Bar trace for volumes
fig.add_trace(go.Bar(x=df['Date'], y=df['AAPL.Volume']),
secondary_y=False)
fig.layout.yaxis2.showgrid=False
fig.show()
Here is my improvement implementation based on the previous answer by Vestland, with some labelling and colouring improvements.
import plotly.graph_objects as go
from plotly.subplots import make_subplots
candlesticks = go.Candlestick(
x=candles.index,
open=candles['open'],
high=candles['high'],
low=candles['low'],
close=candles['close'],
showlegend=False
)
volume_bars = go.Bar(
x=candles.index,
y=candles['volume'],
showlegend=False,
marker={
"color": "rgba(128,128,128,0.5)",
}
)
fig = go.Figure(candlesticks)
fig = make_subplots(specs=[[{"secondary_y": True}]])
fig.add_trace(candlesticks, secondary_y=True)
fig.add_trace(volume_bars, secondary_y=False)
fig.update_layout(title="ETH/USDC pool after Uniswap v3 deployment", height=800)
fig.update_yaxes(title="Price $", secondary_y=True, showgrid=True)
fig.update_yaxes(title="Volume $", secondary_y=False, showgrid=False)
fig.show()
You can find the full source code in this open-source notebook.
If you want to add different colors for buy/sell isay 'green'/'red', you can use some libs (e.g. mplfinance) which do these automatically however the plots are non-interactive. To get interactive plot with plotly with separate colors for buy/sell colors, one needs to add trace for each data point. Here is code:
import plotly.graph_objects as go
from plotly.subplots import make_subplots
import pandas as pd
# Create subplots and mention plot grid size
title=df.symbol.unique()[0]
fig = make_subplots(rows=2, cols=1, shared_xaxes=True,
vertical_spacing=0.02,
row_width=[0.25, 0.75])
# Plot OHLC on 1st row
fig.add_trace(go.Candlestick(x=df.index,
open=df['open'], high=df['high'],
low=df['low'], close=df['close'],showlegend=False),row=1, col=1,)
# Bar trace for volumes on 2nd row without legend
# fig.add_trace(go.Bar(x=df.index, y=df['volume'], showlegend=False), row=2, col=1)
df['color']=''
df['color']=['red' if (x>y) else t for x,y,t in zip(df['open'],df['close'],df['color'])]
df['color']=['green' if (x<y) else t for x,y,t in zip(df['open'],df['close'],df['color'])]
colors=df.color.tolist()
df['prev_color']=[colors[0]]+colors[:(len(colors)-1)]
df.loc[((df.open==df.close) & (df.color=='')),'color']=[z for x,y,z,t in zip(df['open'],df['close'],df['prev_color'],df['color']) if (x==y and t=='')]
colors=df.color.tolist()
df['prev_color']=[colors[0]]+colors[:(len(colors)-1)]
df.loc[((df.open==df.close) & (df.color=='')),'color']=[z for x,y,z,t in zip(df['open'],df['close'],df['prev_color'],df['color']) if (x==y and t=='')]
markers=['green','red']
for t in markers:
df_tmp=df.loc[~(df.color==t)] ## somehow the color it takes is opposite so take negation to
fig.add_trace(go.Bar(x=df_tmp.index, y=df_tmp['volume'], showlegend=False), row=2, col=1)
# Do not show OHLC's rangeslider plot
fig.update(layout_xaxis_rangeslider_visible=False)
fig.layout.yaxis2.showgrid=False
fig.update_layout(title_text=title,title_x=0.45)
fig.show()
My two cents on Plotting Volume in a different subplot with colors, it is just making #user6397960 response shorter without hacks to get the right color, just use marker_color. Think about it, what makes a candle green? The fact of having Close price above the Open price, and what about red candle? well, having a close price below the open price, so with this basics:
import plotly.graph_objects as go
from plotly.subplots import make_subplots
# Create a Figure with 2 subplots, one will contain the candles
# the other will contain the Volume bars
figure = make_subplots(rows=2, cols=1, shared_xaxes=True, row_heights=[0.7, 0.3])
# Plot the candles in the first subplot
figure.add_trace(go.Candlestick(x=df.index, open=df.open, high=df.high, low=df.low, close=df.close, name='price',
increasing_line_color='#26a69a', decreasing_line_color='#ef5350'),
row=1, col=1)
# From our Dataframe take only the rows where the Close > Open
# save it in different Dataframe, these should be green
green_volume_df = df[df['close'] > df['open']]
# Same for Close < Open, these are red candles/bars
red_volume_df = df[df['close'] < df['open']]
# Plot the red bars and green bars in the second subplot
figure.add_trace(go.Bar(x=red_volume_df.index, y=red_volume_df.volume, showlegend=False, marker_color='#ef5350'), row=2,
col=1)
figure.add_trace(go.Bar(x=green_volume_df.index, y=green_volume_df.volume, showlegend=False, marker_color='#26a69a'),
row=2, col=1)
# Hide the Range Slider
figure.update(layout_xaxis_rangeslider_visible=False)
figure.update_layout(title=f'BTC/USDT', yaxis_title=f'Price')
figure.update_yaxes(title_text=f'Volume', row=2, col=1)
figure.update_xaxes(title_text='Date', row=2)
References
https://plotly.com/python/subplots/
https://plotly.com/python/candlestick-charts/
I've been struggling with this seemingly simple task: How to align two x axis with related data. In my case one axis is in Celsius and the other in Fahrenheit.
What I want to achieve is to obtain alignment of the two x axis so that:
32°F = 0°C
And
50°F = 10°C
With this relation, the two datasets will be aligned in terms of temperature.
I want to have both unit sets on the same graph so that the viewer can interpret the data according to the units they are used to.
Here is my code:
import plotly.graph_objects as go
from plotly.subplots import make_subplots
from plotly.graph_objs.layout import YAxis,XAxis,Margin
layout = go.Layout(
title="Double X Axis Example",
xaxis=XAxis(
title="Celcius"
),
xaxis2 = XAxis(
title="Fahrenheits",
overlaying= 'x',
side= 'top',
),
yaxis=dict(
title="Y values"
),
)
# Create figure with secondary x-axis
fig = go.Figure(layout=layout)
# Add traces
fig.add_trace(
go.Scatter(x=[10, 20, 30], y=[4.5, 6, 5], name="data set in celcius"),
)
fig.add_trace(
go.Scatter(x=[40, 60, 80], y=[4, 5, 6.5], name="data set in fahrenheit", xaxis='x2'),
)
fig.show()
Here is the resulting figure with the unaligned axes (10°C = 40°F !?):
Thank you,
In this case it might help to set the ranges for the x-axes, something like this:
fig.add_trace(
go.Scatter(x=[10, 20, 30], y=[4.5, 6, 5,], name="data set in celcius",xaxis="x1"),
)
fig.add_trace(
go.Scatter(x=[40, 60, 80], y=[4, 5, 6.5], name="data set in fahrenheit", xaxis='x2'),
)
fig.update_layout(
xaxis1=dict(range=[0, 100]),
xaxis2=dict(range=[32, 212]),
)
...possibly calculating the limit needed of x1 and then base x2 limit on that.
This is my solution and code to your concern. Here, I set the range of the first and second x axes to [0, 100] and [32, 212], respectively. To align the two axes, I made 26 tick marks for both axes and they are aligned because of the equal number of tick marks. Having an equal number of tick marks for both axes (and equal ranges) is crucial so that the aligned numbers are actually equal. Assuming that most data sets that will be plotted are between 0 and 100 degrees Celsius (for data in Celsius) --- or 32 and 212 degrees Fahrenheit (for data in Fahrenheit) --- I believe this solution overflows the data and the traces won't cover the full x ranges. Plot of the graph here.
import numpy as np
import plotly.graph_objects as go
arr1 = np.array([10, 20, 30])
arr2 = np.array([4.5, 6, 5])
arr3 = np.array([40, 60, 80])
arr4 = np.array([4, 5, 6.5])
fig = go.Figure(go.Scatter( x=arr1, y=arr2, name='data set in celsius' ) )
fig.add_trace(go.Scatter( x=arr3, y=arr4, xaxis='x2', name='data set in fahrenheit' ))
fig.update_layout(title_text='Double X Axis Example',
legend=dict(yanchor='top', y=0.875, xanchor='right', x=1),
yaxis=dict(domain = [0.05, 0.875], title='Y values', spikemode='toaxis', spikesnap='cursor'), template='plotly_dark',
xaxis =dict(position = 0, title='Celsius', spikemode='across', spikesnap='cursor',
tickmode='array', tickvals=np.linspace(0,100,26), range=[0,100]),
xaxis2=dict(position = 0.9, title='Fahrenheit', anchor='free', overlaying='x', side='top', tickmode='array',
tickvals=np.linspace(32,212,26), range=[32,212], spikemode='across', spikesnap='cursor' )
)
fig.show()
I'm trying to create a simple pdf of a subplot consisting of one bar chart and one data table:
The Bar and table function works but when i try and create a subplot plotly gives the following error:
ValueError:
Invalid element(s) received for the 'data' property of
Invalid elements include
I wrote the following: Does it not like that i looped the bar traces?
I first create functions to build the bar chart and data table:
import plotly
import plotly.graph_objects as go
import plotly.figure_factory as ff
import os
import numpy as np
from plotly.subplots import make_subplots
import pandas as pd
def build_barchart(df,columns):
x = df.City.unique() # City column should always be the x axis
fig = go.Figure()
fig.update_layout(barmode='stack')
for column in columns:
Y=df[column].tolist()
fig.add_trace(go.Bar(name=column,x=x,y=Y))
return fig
def build_table(df):
table = ff.create_table(df)
return table
def create_pdf(df,columns):
fig = make_subplots(rows=1, cols=2)
fig.add_trace(
build_barchart(df,columns),
row=1, col=1
)
fig.add_trace(
build_table(df),
row=1, col=2
)
if not os.path.exists("images"):
os.mkdir("images")
fig.write_image("images/fig1.pdf")
return
After creating the build functions i try and use them...
df = pd.read_csv('DATA.csv', delimiter=';')
columns=['%Something','%Dogs','%Cats','%Cars']
table = build_table(df)
bars = build_barchart(df,columns)
fig = make_subplots(rows=1, cols=2)
fig.add_trace(
bars,
row=1, col=1
)
fig.add_trace(
table,
row=1, col=2
)
fig.show()
test data
City;%Something;%Dogs;%Cats;%Cars;Nr Alarms;Nr Block
USA;60;10;5;25;1;1
CANADA;20;10;5;65;2;2
MEXICO;90;5;5;0;3;3
SWEDEN;10;10;5;75;4;4
Please don't take it as an answer. Given that your code has some pitfalls I'm adding a polished version. In particular in case you have duplicated countries x = df.City.astype('str').unique() is not going to work well with Y and you should arrange/check your data before to plot.
import pandas as pd
import plotly.graph_objects as go
from plotly.subplots import make_subplots
df = pd.DataFrame({
'City': {0: 'USA', 1: 'CANADA', 2: 'MEXICO', 3: 'SWEDEN'},
'%Something': {0: 60, 1: 20, 2: 90, 3: 10},
'%Dogs': {0: 10, 1: 10, 2: 5, 3: 10},
'%Cats': {0: 5, 1: 5, 2: 5, 3: 5},
'%Cars': {0: 25, 1: 65, 2: 0, 3: 75},
'Nr Alarms': {0: 1, 1: 2, 2: 3, 3: 4},
'Nr Block': {0: 1, 1: 2, 2: 3, 3: 4}})
def build_subplot(df, columns=None):
if columns is None:
columns = df.columns
# only columns starting with %
columns = [col for col in columns if col.startswith("%")]
fig = make_subplots(rows=1, cols=2,
specs=[
[{"type": "bar"},{"type": "table"}]
]
)
fig.update_layout(barmode='stack')
for column in columns:
fig.append_trace(
go.Bar(x=df["City"],
y=df[column],
name=column),
row=1,col=1)
fig.add_trace(
go.Table(
header=dict(
values=df.columns,
font=dict(size=10),
align="left"
),
cells=dict(
values=df.T.values.tolist(),
align = "left")
),
row=1, col=2
)
return fig
build_subplot(df, ['%Something', '%Dogs', 'Nr Block'])
Addendum: I think it will look better if you can have your subplot with 1 column and 2 rows as some details from the table could be hard to read.
Figured out what i did wrong!
Instead of using plotly.figure_factory's create_table() i used plotly.graph_objects Table()
I also had to define the type of figure used in the creation of the subplot.
The final solution for creating the subplot looks like this:
def build_subplot(df,columns):
x = df.City.astype('str').unique()
fig = make_subplots(rows=1, cols=2,
specs=[
[{"type": "bar"},{"type": "table"}]
]
)
fig.update_layout(barmode='stack')
for column in columns:
Y=df[column].tolist()
fig.append_trace(go.Bar(name=column,x=x,y=Y),row=1,col=1)
fig.add_trace(
go.Table(
header=dict(
values=df.columns,
font=dict(size=10),
align="left"
),
cells=dict(
values=[df[k].tolist() for k in df.columns],
align = "left")
),
row=1, col=2
)
return fig
I hope this helps someone else :)
I want to add horizontal line at 0.09 and -0.09 in every subplot I am generating in plotly. Following is my code to do that.
trace1 = go.Scatter(
x=df1['transaction_date'],
y=df1['difference'],
)
trace2 = go.Scatter(
x=df2['transaction_date'],
y=df2['difference'],
)
trace3 = go.Scatter(
x=df3['transaction_date'],
y=df3['difference'],
)
trace4 = go.Scatter(
x=df4['transaction_date'],
y=df4['difference'],
)
fig = tools.make_subplots(rows=2, cols=2,subplot_titles=('DF1 HS', DF2 HSD',
'DF3 HD', 'DF4 SD',
))
fig.append_trace(trace1, 1, 1)
fig.append_trace(trace2, 1, 2)
fig.append_trace(trace3, 2, 1)
fig.append_trace(trace4, 2, 2)
Then I want to save this 4 subplots as jpeg on disk. How can I do that in python
Try updating layout of fig object with shapes as below:
import plotly.graph_objs as go
from plotly import tools
from plotly.offline import init_notebook_mode, plot
df = pd.DataFrame(np.random.randint(0,100,size=(20,2)),
index=pd.date_range(start='2018-08-21',end='2018-09-09'),
columns=['A','B'])
trace1 = go.Scatter(x=df.index,y=df['A'],)
trace2 = go.Scatter(x=df.index,y=df['B'],)
fig = tools.make_subplots(rows=2, cols=1,subplot_titles=(['A','B']))
fig.append_trace(trace1, 1, 1)
fig.append_trace(trace2, 2, 1)
fig['layout'].update(shapes=[{'type': 'line','y0':50,'y1': 50,'x0':str(df.index[0]),
'x1':str(df.index[-1]),'xref':'x1','yref':'y1',
'line': {'color': 'red','width': 2.5}},
{'type': 'line','y0':50,'y1': 50,'x0':str(df.index[0]),
'x1':str(df.index[-1]),'xref':'x2','yref':'y2',
'line': {'color': 'red','width': 2.5}}])
plot(fig,show_link=False,image='jpeg',image_filename='Temp_plot')
The plot will be saved as Temp_plot.jpeg. Check the image below.
The downside of this method is we need to carefully give axes values to xref and yref with respect to subplots.
I'm pretty new to Plotly so maybe the API has just been updated, but it seems there is a much simpler solution, per the documentation here. One need only use the fig.add_hline() syntax while specifying which subplot (col and row) it should be drawn on, as such:
fig.add_hline(y=1, line_dash="dot", row=1, col=1, line_color="#000000", line_width=2)
This line will instruct Plotly to draw a horizontal line y = 1 on the subplot located at row = 1; col = 1.
Alternatively, as noted in the dox, the "all" keyword can be passed as a value for either the row or col argument to instruct plotly to draw the line on (wait for it...) all the subplots!
You mentioned that you were ok with a matplotlib solution:
Data:
dict = {
"a":np.random.randint(low=-10,high=10,size=20),
"b":np.random.randint(low=-10,high=10,size=20),
"c":np.random.randint(low=-10,high=10,size=20),
"d":np.random.randint(low=-10,high=10,size=20),
}
df = pd.DataFrame(dict)
Plot:
fig, axes = plt.subplots(2,2, figsize=(20,10), sharex=True, sharey=True)
for i,j in zip(axes.ravel(), list(df)):
i.plot(df.index, df[j], 'ro')
i.hlines(y=-3, xmin=0, xmax=22)
i.hlines(y=3, xmin=0, xmax=22)
fig.savefig("testplot.png")
Result: