I am working on a group bar chart in plotly where I have mapped multiple rows in bar chart. Here is the code explaining what I did:
data = [{"Project":"Project A","Features":{"AC":95,"Elec":130, "Area":2349.46, "Cars":30, "Rent":2345.00},"ScaledFeatures":{"AC":95,"Elec":130, "Area":2349.46, "Cars":30, "Rent":2345.00}},
{"Project":"Project B","Features":{"AC":95,"Elec":130, "Area":2120.00, "Cars":42, "Rent":5432},"ScaledFeatures":{"AC":95,"Elec":130, "Area":2120.00, "Cars":42, "Rent":2345}}
]
featureKeys = list(data[0]["Features"].keys())
for key in featureKeys:
featureData = ([d["ScaledFeatures"][key] for d in data])
minimumFeatureValue = min(featureData)
for d in data:
d["ScaledFeatures"][key] = d["ScaledFeatures"][key]/minimumFeatureValue
barData = []
for d in data:
barData.append(go.Bar(name=d['Project'], x=featureKeys, y=list(d["ScaledFeatures"].values()),text=list(d["Features"].values()),textposition='auto'))
# set plot layout
layout = go.Layout(
xaxis={"mirror" : "allticks", 'side': 'top'} # x-axis also at top
)
fig = go.Figure(data=barData,layout=layout)
# Change the bar mode
#fig.update_traces(textposition='outside')
fig.update_layout(barmode='group')
fig.show()
Here is the output it generates:
I want to generate the following like output from this where legends are coming in x-axis:
What I have done till now is to use multiple axes but that draws its own bars n the same chart. Any help is appreciated!
You could use multicategory x axes here, as in this example. However you would have A/B and AC/Elec etc. together on the same side. If you don't want to use this you can use annotations https://plot.ly/python/text-and-annotations/#simple-annotation. Also, here you could consider using px.bar from plotly.express: https://plot.ly/python/bar-charts/
Related
I can create a simple bar chart with the code below, but I want to add error bars if that is even possible.
gm12878_close_TAD_df = pd.DataFrame(gm12878_close, columns=['distance'])
gm12878_close_TAD_df_500kb = gm12878_close_TAD_df[gm12878_close_TAD_df['distance'] < 10000]
alt.Chart(gm12878_close_TAD_df_500kb).mark_bar().encode(x = alt.X('distance', bin=alt.Bin(maxbins=30)), y='count()')
Which produces this chart:
CHART PRODUCED HERE
To add error bars I have been trying to use something like this based off this link (https://altair-viz.github.io/gallery/grouped_bar_chart_with_error_bars.html)
chart = alt.Chart(gm12878_close_TAD_df_500kb).mark_bar().encode(x = alt.X('distance', bin=alt.Bin(maxbins=30)), y='count()')
error_bars = chart.mark_errorbar(extent='ci').encode(x = 'distance', y='count():Q')
alt.layer(chart, error_bars)
I would appreciate any suggestions and help. Thank you in advanced.
You cannot create an error bar from a count because it is a single number; an error bar needs multiple values within the same group to derive a measure of uncertainty such as a confidence interval. You would also need to bin the x-axis for the error bar, so that it corresponds to the axis of the other layered chart. Here is an example
import altair as alt
from vega_datasets import data
source = data.movies.url
mean_points = alt.Chart(source).mark_circle(color='black').encode(
alt.X("IMDB_Rating:Q", bin=True),
y='mean(Worldwide_Gross):Q',
)
error_bars = alt.Chart(source).mark_errorbar(extent='ci').encode(
alt.X("IMDB_Rating:Q", bin=True),
y='Worldwide_Gross:Q',
)
mean_points + error_bars
I am trying to plot a subplot which contains 14 candlestick charts of cryptocurrency data. (
https://www.kaggle.com/c/g-research-crypto-forecasting)
However, it seems that it can't display the figure properly.
Here is my code:
from plotly import subplots
import plotly.graph_objects as go
fig = subplots.make_subplots(rows=7,cols=2)
for ix,coin_name in enumerate(asset_details["Asset_Name"]):
coin_df = crypto_df[crypto_df["Asset_ID"]==asset_names_dict[coin_name]].set_index("timestamp")
coin_df_mini = coin_df.iloc[-100:]
column = lambda ix: 1 if ix % 2 == 0 else 2
candlestick = go.Candlestick(x=coin_df_mini.index, open=coin_df_mini['Open'], high=coin_df_mini['High'], low=coin_df_mini['Low'], close=coin_df_mini['Close'])
fig = fig.add_trace(candlestick, row=((ix//2) + 1), col=column(ix))
fig.update_layout(xaxis_rangeslider_visible=False)
fig.update_layout(title_text="Candlestick Charts", height=2800)
fig.show()
And here is the problem:
rangeslider_problem
No matter I plot the figure with or without the rangeslider, it's always out of shape.
You need to hide the slider on the x-axis unit created in the subplot. My answer was to do all the subplots manually. I don't have time to deal with this right now, but there is also a way to update the output content in a loop process.
fig.update_layout(xaxis1=dict(rangeslider=dict(visible=False)),
xaxis2=dict(rangeslider=dict(visible=False)),
xaxis3=dict(rangeslider=dict(visible=False)),
xaxis4=dict(rangeslider=dict(visible=False)),
xaxis5=dict(rangeslider=dict(visible=False)),
xaxis6=dict(rangeslider=dict(visible=False)),
xaxis7=dict(rangeslider=dict(visible=False)),
xaxis8=dict(rangeslider=dict(visible=False)),
xaxis9=dict(rangeslider=dict(visible=False)),
xaxis10=dict(rangeslider=dict(visible=False)),
xaxis11=dict(rangeslider=dict(visible=False)),
xaxis12=dict(rangeslider=dict(visible=False)),
xaxis13=dict(rangeslider=dict(visible=False)),
xaxis14=dict(rangeslider=dict(visible=False)),
)
I'm trying to create a bar chart to see which stores had the biggest revenue in my dataset. Using the default Pandas plot I can do that in one line:
df.groupby('store_name')['sale_value'].sum().sort_values(ascending=False).head(20).plot(kind='bar')
But this chart is not very interactive and I can't see the exact values, so I want to try and create it using Bokeh and be able to mouseover a bar and see the exact amout, for example.
I tried doing the following but just got a blank page:
source = ColumnDataSource(df.groupby('store_name')['sale_value'])
plot = Plot()
glyph = VBar(x='store_name', top='sale_value')
plot.add_glyph(source, glyph)
show(plot)
and if I change source to ColumnDataSource(df.groupby('store_name')['sale_value'].sum()) I get 'ValueError: expected a dict or pandas.DataFrame, got store_name'
How can I create this chart with mouseover using Bokeh?
Let's asume this is our DataFrame:
df = pd.DataFrame({'store_name':['a', 'b', 'a', 'c'], 'sale_value':[4, 5, 2, 4]})
df
>>>
store_name sale_value
0 a 4
1 b 5
2 a 2
3 c 4
Now it is possible to creat a bar chart with your approach.
First we have to do some imports and preprocessing:
from bokeh.models import ColumnDataSource, Grid, LinearAxis, Plot, VBar, Title
source = ColumnDataSource(df.groupby('store_name')['sale_value'].sum().to_frame().reset_index())
my_ticks = [i for i in range(len(source.data['store_name']))]
my_tick_labels = {i: source.data['store_name'][i] for i in range(len(source.data['store_name']))}
There are some changes in the section of the groupby. A .sum() is added and it is reset to a DataFrame with ascending index.
Then you can create a plot.
plot = Plot(title=Title(text='Plot'),
plot_width=300,
plot_height=300,
min_border=0,
toolbar_location=None
)
glyph = VBar(x='index',
top='sale_value',
bottom=0,
width=0.5,
fill_color="#b3de69"
)
plot.add_glyph(source, glyph)
xaxis = LinearAxis(ticker = my_ticks,
major_label_overrides= my_tick_labels
)
plot.add_layout(xaxis, 'below')
yaxis = LinearAxis()
plot.add_layout(yaxis, 'left')
plot.add_layout(Grid(dimension=0, ticker=xaxis.ticker))
plot.add_layout(Grid(dimension=1, ticker=yaxis.ticker))
show(plot)
I also want to show your a second approach I prefere more.
from bokeh.plotting import figure, show
plot = figure(title='Plot',
plot_width=300,
plot_height=300,
min_border=0,
toolbar_location=None
)
plot.vbar(x='index',
top='sale_value',
source=source,
bottom=0,
width=0.5,
fill_color="#b3de69"
)
plot.xaxis.ticker = my_ticks
plot.xaxis.major_label_overrides = my_tick_labels
show(plot)
I like the second one more, because it is a bit shorter.
The created figure is in both cases the same. It looks like this.
Backstory: I absolutely have to use matplotlib for this, sadly. I need to create a grouped bar chart. I do not know how many traces the chart will have, so i can not explicitly state the width for each. As of now, this is the relevant code;
fig = plt.figure()
...
...
...
if np.mean(height) > 4000 and len(height) > 6:
label = page.split(' (')[0].split(' ')
label = ' '.join(label[-2:])
ax1 = ax.bar(
x=[d for d in dates],
height=[v / 1000 for v in vals.values()],
label=label
)
Attached is the plot
make me grouped and not stacked
I have a pandas DataFrame with a DateTime index.
I can plot a timeseries from it, and by default it looks fine.
But when I try to print a bar chart from the same DataFrame, the xAxis labels are ruined (massive overlapping). (Also the spacing of the data is weird (big gaps between sets of bars)
I tried autoformat_xdate(), but that didn't help anything.
This is the simple code fragment I used to generate the charts
entire_df['predict'] = regr.predict(entire_df[X_cols])
entire_df['error'] = entire_df['predict']-entire_df['px_usd_mmbtu']
#entire_df['error'].plot(kind='hist')
fig=plt.figure()
entire_df[['px_usd_mmbtu', 'predict']].plot()
fig2 = plt.figure()
entire_df['error'].plot(kind='bar')
#fig2.autofmt_xdate() #doesn't help
print (type(error_df.index))
Try this:
entire_df['predict'] = regr.predict(entire_df[X_cols])
entire_df['error'] = entire_df['predict']-entire_df['px_usd_mmbtu']
plt.figure(figsize=(15,15))
plt.xticks(rotation = 90) # or change from 90 to 45
#entire_df['error'].plot(kind='hist')
entire_df[['px_usd_mmbtu', 'predict']].plot()
entire_df['error'].plot(kind='bar')