I have been trying to plot sorted barplot in plotly for some stores sales data, but whatever I try it gives me the unsorted data. How to plot the sorted barplot using plotly.
NOTE:
https://community.plot.ly/t/sort-bars-in-bar-chart-by-value-and-have-each-bar-with-a-different-color/14562
Did not worked for me.
Data
import numpy as np
import pandas as pd
import plotly
import plotly.offline as py
import plotly.graph_objs as go
from plotly.offline import plot, iplot, init_notebook_mode
init_notebook_mode(connected=False)
print([(x.__name__,x.__version__) for x in [np, pd,plotly]])
url = "https://github.com/bhishanpdl/Datasets/blob/master/store_item_demand/train_store_item_demand.csv?raw=true"
df = pd.read_csv(url, parse_dates=['date'],index_col=['date'])
Using pandas (gives sorted barplot)
df1 = df.groupby('store')['sales'].sum().sort_values()
df1.plot.bar()
Using plotly3.10 (gives unsorted barplot) (How to fix this?)
def barplot(x,y):
data = [go.Bar(
x=x,
y=y,
marker={
'color': y,
'colorscale': 'Reds'
}
)]
layout = {
'xaxis': {
'tickvals': x,
'ticktext': ['store ' + str(i) for i in x],
'tickangle': 40
}
}
fig = go.FigureWidget(data=data, layout=layout)
return iplot(fig)
# plot
df1 = df.groupby('store')['sales'].sum().sort_values()
x = df1.index.values
y = df1.values
barplot(x,y)
outputs
Question
How to get sorted barplot using plotly3.10 ?
Related link
https://community.plot.ly/t/sort-bars-in-bar-chart-by-value-and-have-each-bar-with-a-different-color/14562
Did not work for me.
The correct key to use for this is layout.xaxis.categoryorder, with the value "total ascending", but it only applies when the layout.xaxis.type is "category". This happens automatically if your x array contains strings, but if your x contains only numbers you'll have to set it manually.
Here is a version of your barplot function as recommended:
def barplot(x,y):
data = [go.Bar(
x=x,
y=y,
marker={
'color': y,
'colorscale': 'Reds'
}
)]
layout = {
'xaxis': {
'tickvals': x,
'ticktext': ['store ' + str(i) for i in x],
'tickangle': 40,
'type': "category",
'categoryorder': 'total ascending'
}
}
fig = go.FigureWidget(data=data, layout=layout)
return iplot(fig)
Related
import plotly.express as px
import pandas as pd
data = pd.read_csv("Book1.csv")
fig = px.scatter(data, y="Category", x="Mean", color="Change")
fig.update_layout(
xaxis=dict(title="Title",range=[2,3],),
yaxis=dict(title="Mean"),
title="Title"
)
fig.update_traces(marker=dict(size=30,
line=dict(width=2,
color='DarkSlateGrey')),
selector=dict(mode='markers'))
fig.show()
I want to make the circles clearer, like more spaced out or scattered. Do you have any suggestions?
Here is the plot:
There is a technique called jittering where you add a small amount of noise to make it less likely for the circles to overlap as much as in your sample figure. It's not perfect, but here is an example of what you can accomplish. You can also try regenerating the plot with a different amount of jittering, as well as different random seeds until you are happy with the result.
import plotly.express as px
import numpy as np
import pandas as pd
# data = pd.read_csv("Book1.csv")
data = pd.DataFrame({
'Category': ['More than usual']*5 + ['About the same']*5 + ['Less than usual']*5,
'Mean': [2.2,2.4,2.22,2.24,2.6] + [2.4,2.41,2.5,2.1,2.12] + [2.81,2.1,2.5,2.45,2.42],
'Change': [1]*5 + [2]*5 + [3]*5
})
category_to_value_map = {
'Less than usual': 1,
'About the same': 2,
'More than usual': 3
}
data['y'] = data['Category'].map(category_to_value_map)
## apply jittering
max_jittering = 0.15
np.random.seed(4)
data['y'] = data['y'] + np.random.uniform(
low=-1*max_jittering,
high=max_jittering,
size=len(data)
)
fig = px.scatter(data, y="y", x="Mean", color="Change")
fig.update_layout(
xaxis=dict(title="Title",range=[2,3],),
yaxis=dict(title="Mean"),
title="Title"
)
fig.update_traces(marker=dict(size=20,
line=dict(width=2,
color='DarkSlateGrey')),
selector=dict(mode='markers'))
fig.update_layout(
yaxis = dict(
tickmode = 'array',
tickvals = [1, 2, 3],
ticktext = ['Less than usual', 'About the same', 'More than usual']
)
)
fig.show()
Trying to add data to hover of boxplot express in plotly and following the instructions here in plotly 5.4.1. It is mentioned in the tutorial that additional information to be shown in the hover can be added by hover_data and hover_name argument. However, The additional hover data, in this case information from continent column, is not presented in the hover. I am not sure what is going wrong here? (Here is the code I test in Google colab)
import plotly.express as px
import pandas as pd
import numpy as np
np.random.seed(1234)
df = pd.DataFrame(np.random.randn(20, 1),columns=['Col1'])
df['country']=['canada','france']*10
df['continent']=['america','europe']*10
fig = px.box(df, x="country", y="Col1", hover_data=['continent'])
fig.show()
Here is what i get in google colab:
Error I get with suggested solution (this was solved with pip install plotly --upgrade):
The solution offered by #Rob works but to make it a generic function, here is what I wrote out of it:
def box_with_hover(df,x,y,hover_data):
fig = px.box(df, x=x, y=y, hover_data=[hover_data])
fig.add_traces(
px.bar(
df.groupby([x, hover_data], as_index=False).agg(
base=(y, "min"), y=(y, lambda s: s.max() - s.min())
),
x=x,
base="base",
y="y",
hover_data={hover_data:True, x:True, "base":False, "y":False},
)
.update_traces(opacity=0.1)
.data ).update_layout(bargap=0.8)
fig.show()
this is similar to Change Plotly Boxplot Hover Data
boxplot hover info is within javascript layer of plotly. Hence have overlayed a bar plot where hover can be controlled in way you require. When you hover over boxplot you get standard boxplot hover. bar different hover info
import plotly.express as px
import pandas as pd
import numpy as np
np.random.seed(1234)
df = pd.DataFrame(np.random.randn(20, 1), columns=["Col1"])
df["country"] = ["canada", "france"] * 10
df["continent"] = ["america", "europe"] * 10
fig = px.box(df, x="country", y="Col1", hover_data=["continent"])
fig.add_traces(
px.bar(
df.groupby(["country", "continent"], as_index=False).agg(
base=("Col1", "min"), y=("Col1", lambda s: s.max() - s.min())
),
x="country",
base="base",
y="y",
hover_data={"continent":True, "country":True, "base":False, "y":False},
)
.update_traces(opacity=0.1)
.data
).update_layout(bargap=0.8)
fig
generic function
import plotly.express as px
import pandas as pd
import numpy as np
np.random.seed(1234)
df = pd.DataFrame(np.random.randn(20, 1), columns=["Col1"])
df["country"] = ["canada", "france"] * 10
df["continent"] = ["america", "europe"] * 10
df["letter"] = list("AB") * 10
def box_with_hover(*args, **kwargs):
if isinstance(args[0], pd.DataFrame):
kwargs["data_frame"] = args[0]
fig = px.box(**kwargs)
fig.add_traces(
px.bar(
kwargs["data_frame"]
.groupby([kwargs["x"]], as_index=False)
.agg(
**{
**{
"base": (kwargs["y"], "min"),
"y": (kwargs["y"], lambda s: s.max() - s.min()),
},
**{c: (c, "first") for c in kwargs["hover_data"]},
}
),
x=kwargs["x"],
base="base",
y="y",
hover_data={
**{c: True for c in kwargs["hover_data"]},
**{kwargs["x"]: True, "base": False, "y": False},
},
)
.update_traces(opacity=0.1)
.data
).update_layout(bargap=0.8)
return fig
box_with_hover(
df.reset_index(), x="country", y="Col1", hover_data=["continent", "letter", "index"]
)
I wanted to create an interactive plot with matplotlib in google colab. It seems like a complex task so I want a little help to convert this piece of code which is in matplotlib to Plotly.
close = df['A']
fig = plt.figure(figsize = (15,5))
plt.plot(close, color='r', lw=2.)
plt.plot(close, '^', markersize=10, color='m', label = 'signal X', markevery = df_x)
plt.plot(close, 'v', markersize=10, color='k', label = 'signal Y', markevery = df_y)
plt.title('Turtle Agent: total gains %f, total investment %f%%'%(df_A, df_B))
plt.legend()
plt.show()
using sample data from plotly OHLC examples https://plotly.com/python/ohlc-charts/
create a line trace
add scatter traces based on filters of data frame with required formatting. This is done as a list comprehension, could be done as inline code
import pandas as pd
import numpy as np
import plotly.express as px
df = pd.read_csv(
"https://raw.githubusercontent.com/plotly/datasets/master/finance-charts-apple.csv"
)
df["Date"] = pd.to_datetime(df["Date"])
# make data set more useful for demonstrating this plot
df.loc[df.sample((len(df)//8)*7).index, "direction"] = np.nan
px.line(df, x="Date", y="AAPL.Close").update_traces(line_color="red").add_traces(
[
px.scatter(
df.loc[df["direction"].eq(filter)], x="Date", y="AAPL.Close"
)
.update_traces(marker=fmt)
.data[0]
for filter, fmt in zip(
["Increasing", "Decreasing"],
[
{"color": "black", "symbol": "triangle-up", "size": 10},
{"color": "blue", "symbol": "triangle-down", "size": 10},
],
)
]
)
For research data visualisation I'd like to make an animated 3D surface plot in Plotly. The goal is to see the evolution of temperature in a box in function of time. But I don't know how to animate it.
At this moment I only have my plot at a give time.
This is my code:
import plotly
import plotly.graph_objects as go
#import plotly.express as px
import pandas as pd
#import numpy as np
#read CSV
z_data = pd.read_csv('data1.csv')# Read data from a csv
fig = go.Figure(data=[go.Surface(z=z_data.values)])
#projection 2D
fig.update_traces(contours_z=dict(show=True, usecolormap=True,
highlightcolor="tomato", project_z=True),
colorscale='portland')
#fig
fig.update_layout(title='data HEATPILES', autosize=False, width=650, height=500, margin=dict(l=0, r=0, b=0, t=0))
#show
plotly.offline.plot(fig)
data1.csv is only this:
data1.csv
But I have more data of the point's position in function of time and I would want to make an animated plot, so we could clearly see the evolution on time.
Here is the result at a given time
Plot at a given time
I've seen on the plotly documentation that it's possible to make animation with px.scatter and px.line from here, and from there that we can do it with image, so I guess it would be possible with surface plot.
Here is some example of the animation: https://plotly.com/python/#animations
Here is some example of the 3D surface plot: https://plotly.com/python/3d-surface-plots
If you could help me do you I would much appreciate !
Thank you for your help,
Theophile
Here is the full code for you:
import pandas as pd
import plotly.graph_objects as go
z_data = pd.read_csv('https://raw.githubusercontent.com/plotly/datasets/master/api_docs/mt_bruno_elevation.csv').values
print(z_data)
z_data2 = z_data * 1.1
z_data3 = z_data * 1.2
z_data4 = z_data * 0.5
z_data_list = []
z_data_list.append(z_data)
z_data_list.append(z_data2)
z_data_list.append(z_data3)
z_data_list.append(z_data4)
z_data_list.append(z_data)
z_data_list.append(z_data2)
z_data_list.append(z_data3)
z_data_list.append(z_data4)
fig = go.Figure(
data=[go.Surface(z=z_data_list[0])],
layout=go.Layout(updatemenus=[dict(type="buttons", buttons=[dict(label="Play", method="animate", args=[None])])]),
frames=[go.Frame(data=[go.Surface(z=k)], name=str(i)) for i, k in enumerate(z_data_list)]
)
fig.update_traces(contours_z=dict(show=True, usecolormap=True, highlightcolor="tomato", project_z=True), colorscale='portland')
fig.update_layout(title='data HEATPILES', autosize=False, width=650, height=500, margin=dict(l=0, r=0, b=0, t=0))
def frame_args(duration):
return {
"frame": {"duration": duration},
"mode": "immediate",
"fromcurrent": True,
"transition": {"duration": duration, "easing": "linear"},
}
sliders = [
{
"pad": {"b": 10, "t": 60},
"len": 0.9,
"x": 0.1,
"y": 0,
"steps": [
{
"args": [[f.name], frame_args(0)],
"label": str(k),
"method": "animate",
}
for k, f in enumerate(fig.frames)
],
}
]
fig.update_layout(sliders=sliders)
import plotly.io as pio
ii = 1
pio.write_html(fig, file="Live3D_"+str(ii)+".html", auto_open=True)
# plotly.offline.plot(fig)
After a good research I built this code to plot a proper smooth 3D surface plot. Simply put the data_frame into this function. You'll get a proper smoothen surface plot. Incase you face any error, just choose only those features from data_frame which are numerical.
'data_frame = data_frame.select_dtypes(include='number')'
from scipy import interpolate
from mpl_toolkits.mplot3d import axes3d, Axes3D
def surface(data_frame, title=None, title_x=0.5, title_y=0.9):
X, Y = np.mgrid[-10:10:complex(0,data_frame.shape[0]),
-10:10:complex(0,data_frame.shape[1])]
Z = data_frame.values
xnew, ynew = np.mgrid[-1:1:80j, -1:1:80j]
tck = interpolate.bisplrep(X, Y, Z, s=0)
znew = interpolate.bisplev(xnew[:,0], ynew[0,:], tck)
fig = go.Figure(data=[go.Surface(z=znew)])
fig.update_layout(template='plotly_dark',
width=800,
height=800,
title = title,
title_x = title_x,
title_y = title_y
)
return fig
I want to plot a scatter_mapbox plot over a choropleth_mapbox plot using plotly. I want to use Picnic for the scatter_mapbox plot's color scale. When I run this, the scatter_mapbox colorscale is set to the same properties as the choropleth_mapbox properties. Namely, it uses the color scale Viridis instead of Picnic and uses the choropleth's numerical scale. How can I make the the colorscale for the scatterplot Picnic.
import numpy as np
import pandas as pd
import geopandas as gpd
import plotly.express as px
import geopandas as gpd
import shapely
df = px.data.election()
df = gpd.GeoDataFrame.from_features(
px.data.election_geojson()["features"]
).merge(df, on="district").set_index("district")
df = df.loc[df['geometry'].map(lambda x: type(x) == shapely.geometry.polygon.Polygon)]
df2 = df.copy()
df2['geometry'] = df2['geometry'].map(lambda x: x.exterior.coords[0]).map(shapely.geometry.Point)
#make the charts
map_fig = px.choropleth_mapbox(
df,
geojson=df.geometry,
locations=df.index,
color='Bergeron',
center= { 'lon': df2.geometry.x.iloc[0], 'lat': df2.geometry.y.iloc[0]},
color_continuous_scale="Viridis",
mapbox_style="carto-positron",
opacity = 0.2,
)
map_fig2 = px.scatter_mapbox(
df2,
lat=df2.geometry.y,
lon=df2.geometry.x,
size='Bergeron',
zoom=12,
color='Bergeron', color_continuous_scale='Picnic',
opacity = 1,
size_max=10
)
map_fig.add_trace(map_fig2.data[0])
map_fig.update_geos(fitbounds="locations", visible=False)
map_fig.show()
A step in the right direction is to add this, which puts the scatter_mapbox on a separate coloraxis, but sets the color scale to the plotly default, Plasma, instead of Picnic, as specified. It also overlays the colorbar.
'color' : np.array(df2['Bergeron']),
'coloraxis' : 'coloraxis2',
'opacity' : 1,
'colorscale' : 'Picnic',
'sizemode' : 'area',
'sizeref' : .01,
'autocolorscale' : False
}
If this is what you're aiming to do:
Then follow these steps in addition to what you're already doing:
1. Steal the coloraxis from fig2 where color='Picnic' to fig with:
fig.layout.coloraxis2 = fig2.layout.coloraxis
2. Include the second trace with:
fig.add_trace(fig2.data[0])
3. Assign colors to the second trace with:
fig['data'][1]['marker'] = { 'color' : np.array(df2['Bergeron']),
'coloraxis' : 'coloraxis2',
}
4. Move the second colorbar to a more suitable place with:
fig.layout.coloraxis2.colorbar.x = -0.2
The third step makes the colors for the second trace available through 'coloraxis' : 'coloraxis2'
I hope this is what you were looking for. Don't hesitate to let me know if not!
Complete code:
(Sorry, I got tired of typing map_fig so I change the references to merely fig)
import numpy as np
import pandas as pd
import geopandas as gpd
import plotly.express as px
import geopandas as gpd
import shapely
df = px.data.election()
df = gpd.GeoDataFrame.from_features(
px.data.election_geojson()["features"]
).merge(df, on="district").set_index("district")
df = df.loc[df['geometry'].map(lambda x: type(x) == shapely.geometry.polygon.Polygon)]
df2 = df.copy()
df2['geometry'] = df2['geometry'].map(lambda x: x.exterior.coords[0]).map(shapely.geometry.Point)
#make the charts
fig = px.choropleth_mapbox(
df,
geojson=df.geometry,
locations=df.index,
color='Bergeron',
center= { 'lon': df2.geometry.x.iloc[0], 'lat': df2.geometry.y.iloc[0]},
color_continuous_scale="Viridis",
mapbox_style="carto-positron",
opacity = 0.2,
)
fig2 = px.scatter_mapbox(
df2,
lat=df2.geometry.y,
lon=df2.geometry.x,
size='Bergeron',
zoom=12,
color='Bergeron',
color_continuous_scale='picnic',
opacity = 1,
size_max=10
)
fig.add_trace(fig2.data[0])
fig.layout.coloraxis2 = fig2.layout.coloraxis
fig['data'][1]['marker'] = { 'color' : np.array(df2['Bergeron']),
'coloraxis' : 'coloraxis2',
'opacity' : 1,
'sizemode' : 'area',
'sizeref' : .01,
'autocolorscale' : False
}
fig.update_geos(fitbounds="locations", visible=False)
fig.layout.coloraxis2.colorbar.x = -0.2
fig.show()