So I have the following code:
workload_df = pd.DataFrame({
'index': pd.to_datetime(['01.02.2010', '01.03.2010', '01.04.2010']),
'measure': [100, 90, 120],
'measure_max': [80, 100, 150],
})
measure_max_plot = alt.Chart(workload_df).mark_bar(color = 'lightgreen', text = 'measure_max').encode(
alt.X('index', title = '', axis = alt.Axis(labelAngle = -45, labelOverlap = False)),
alt.Y('measure_max', title = '')
)
measure_plot = alt.Chart(workload_df).mark_bar(text = 'measure').encode(
x = alt.X('index', title = 'X', axis = alt.Axis(labelAngle = -45, labelOverlap = False)),
y = alt.Y('measure', title = 'Y'),
color=alt.condition(
alt.datum.measure > alt.datum.measure_max,
alt.value('red'),
alt.value('steelblue')
)
)
altair_plot = alt.layer(measure_max_plot, measure_plot)
st.altair_chart(altair_plot, use_container_width=True)
I already tried adding a legend, by using this solution:
Add legend to line & bars to Altair chart without using size/color
But got a weird error all the time or got a legend without any plotted data.
Can anyone help me with that?
In order to add a legend to your chart, you will need an encoding that the legend will represent. For example, here's how you might add a color encoding that will generate a color legend:
measure_max_plot = alt.Chart(workload_df).transform_calculate(
color='"measure_max"'
).mark_bar(text = 'measure_max').encode(
alt.X('index', title = '', axis = alt.Axis(labelAngle = -45, labelOverlap = False)),
alt.Y('measure_max', title = ''),
alt.Color('color:N')
)
measure_plot = alt.Chart(workload_df).transform_calculate(
color="datum.measure > datum.measure_max ? 'bigger' : 'smaller'"
).mark_bar(text = 'measure').encode(
x = alt.X('index', title = 'X', axis = alt.Axis(labelAngle = -45, labelOverlap = False)),
y = alt.Y('measure', title = 'Y'),
color = alt.Color('color:N', scale=alt.Scale(range=['red', 'lightgreen', 'steelblue']))
)
altair_plot = alt.layer(measure_max_plot, measure_plot)
Notice that by default, the color scale is shared between the two layered charts. This behavior can be fine-tuned using the Scale & guide resolution API.
Related
I want to keep the labels when you hover, but hide the labels from just appearing over the Sankey as text.
Here is my code:
labels = df_mapping['Name'].to_numpy().tolist() + labels
count_dict = {}
source = []
target = []
value = df_subset['Stuff'].to_numpy().tolist()
index = 0
for x in unique_broad:
count_dict[x] = len(df_mapping.loc[df_mapping['Stuff'] == x])
for key in count_dict:
for i in range(count_dict[key]):
source.append(index)
index += 1
for key in count_dict:
for i in range(count_dict[key]):
target.append(index)
index += 1
number_of_colors = len(source)
color_link = ["#"+''.join([random.choice('0123456789ABCDEF') for j in range(6)])
for i in range(number_of_colors)]
link = dict(source=source, target=target, value=value, color=color_link)
node = dict(label=labels, pad=35, thickness=10)
data = go.Sankey(link=link, node=node)
fig = go.Figure(data)
fig.update_layout(
hovermode = 'x',
title="Sankey for Stuff",
font=dict(size=8, color='white'),
paper_bgcolor='#51504f'
)
return fig
You can make the labels invisible by setting the color of the labels to rgba(0,0,0,0). This ensures that the label will remain in the hovertemplate, but not show up on the nodes.
To do this you can pass textfont=dict(color="rgba(0,0,0,0)", size=1) to go.Sankey such as in the example you used from the Plotly sankey diagram documentation:
import plotly.graph_objects as go
import urllib.request, json
url = 'https://raw.githubusercontent.com/plotly/plotly.js/master/test/image/mocks/sankey_energy.json'
response = urllib.request.urlopen(url)
data = json.loads(response.read())
# override gray link colors with 'source' colors
opacity = 0.4
# change 'magenta' to its 'rgba' value to add opacity
data['data'][0]['node']['color'] = ['rgba(255,0,255, 0.8)' if color == "magenta" else color for color in data['data'][0]['node']['color']]
data['data'][0]['link']['color'] = [data['data'][0]['node']['color'][src].replace("0.8", str(opacity))
for src in data['data'][0]['link']['source']]
fig = go.Figure(data=[go.Sankey(
textfont=dict(color="rgba(0,0,0,0)", size=1),
valueformat = ".0f",
valuesuffix = "TWh",
# Define nodes
node = dict(
pad = 15,
thickness = 15,
line = dict(color = "black", width = 0.5),
label = data['data'][0]['node']['label'],
color = data['data'][0]['node']['color']
),
# Add links
link = dict(
source = data['data'][0]['link']['source'],
target = data['data'][0]['link']['target'],
value = data['data'][0]['link']['value'],
label = data['data'][0]['link']['label'],
color = data['data'][0]['link']['color']
))])
fig.update_layout(title_text="Energy forecast for 2050<br>Source: Department of Energy & Climate Change, Tom Counsell via <a href='https://bost.ocks.org/mike/sankey/'>Mike Bostock</a>",
font_size=10)
fig.show()
You get the following:
Description
This code shows three Altair charts:
scatter
rate
line_plot
Goal
The goal is to combine all charts into a layered chart w/ these specifications:
show the y-axis for both scatter and rate (ie. dual axis chart)
facet by Series
show the line_plot.
Code
import altair as alt
from vega_datasets import data
import pandas as pd
source = data.anscombe().copy()
source['line-label'] = 'x=y'
source = pd.concat([source,source.groupby('Series').agg(x_diff=('X','diff'), y_diff=('Y','diff'))],axis=1)
source['rate'] = source.y_diff/source.x_diff
source['rate-label'] = 'rate of change'
source['line-label'] = 'line y=x'
source_linear = source.groupby(by=['Series']).agg(x_linear=('X','max'), y_linear=('X', 'max')).reset_index().sort_values(by=['Series'])
source_origin = source_linear.copy()
source_origin['y_linear'] = 0
source_origin['x_linear'] = 0
source_linear = pd.concat([source_origin,source_linear]).sort_values(by=['Series'])
source = source.merge(source_linear,on='Series').drop_duplicates()
scatter = alt.Chart(source).mark_circle(size=60, opacity=0.60).encode(
x=alt.X('X', title='X'),
y=alt.Y('Y', title='Y'),
color='Series:N',
tooltip=['X','Y','rate']
)
line_plot = alt.Chart(source).mark_line(color= 'black', strokeDash=[3,8]).encode(
x=alt.X('x_linear', title = ''),
y=alt.Y('y_linear', title = ''),
shape = alt.Shape('line-label', title = 'Break Even'),
color = alt.value('black')
)
rate = alt.Chart(source).mark_line(strokeDash=[5,3]).encode(
x=alt.X('X', title = 'X'),
y=alt.Y('rate:Q'),
color = alt.Color('rate-label',),
tooltip=['rate','X','Y']
)
Current solution
The issue with the current solution is that the rate chart's y-axis is not displaying as a dual axis. Any suggestions?
alt.layer(rate,scatter,line_plot).facet(
'Series:N'
, columns=2
).resolve_scale(
x='independent',
y='independent'
).display()
Well, I got it, but this probably isn't the best solution. I've followed the method described in the following link where we manually facet the charts:
Thread on Facets
To get the dual axis, I just added .resolve_scale(y='independent') to the manual step. Below is the solution:
import altair as alt
from vega_datasets import data
import pandas as pd
source = data.anscombe().copy()
source\['line-label'\] = 'x=y'
source = pd.concat(\[source,source.groupby('Series').agg(x_diff=('X','diff'), y_diff=('Y','diff'))\],axis=1)
source\['rate'\] = source.y_diff/source.x_diff
source\['rate-label'\] = 'rate of change'
source\['line-label'\] = 'line y=x'
source_linear = source.groupby(by=\['Series'\]).agg(x_linear=('X','max'), y_linear=('X', 'max')).reset_index().sort_values(by=\['Series'\])
source_origin = source_linear.copy()
source_origin\['y_linear'\] = 0
source_origin\['x_linear'\] = 0
source_linear = pd.concat(\[source_origin,source_linear\]).sort_values(by=\['Series'\])
source = source.merge(source_linear,on='Series').drop_duplicates()
scatter = alt.Chart().mark_circle(size=60, opacity=0.60).encode(
x=alt.X('X', title='X'),
y=alt.Y('Y', title='Y'),
color='Series:N',
tooltip=\['X','Y','rate'\]
)
line_plot = alt.Chart().mark_line(color= 'black', strokeDash=\[3,8\]).encode(
x=alt.X('x_linear', title = '', axis=None),
y=alt.Y('y_linear', title = '', axis=None),
shape = alt.Shape('line-label', title = 'Break Even'),
color = alt.value('black')
)
rate = alt.Chart().mark_line(strokeDash=\[5,3\]).encode(
x=alt.X('X', title = 'X'),
y=alt.Y('rate:Q'),
color = alt.Color('rate-label',),
tooltip=\['rate','X','Y'\]
)
scatter_rate = alt.layer(scatter, rate, data=source)
chart_generator = (alt.layer(scatter, rate, line_plot, data = source, title=f"{val}: Duplicated Points w/ Line at Y=X").transform_filter(alt.datum.Series == val).resolve_scale(y='independent') \
for val in source.Series.unique())
chart = alt.concat(*(
chart_generator
), columns=2).display()
Which line of this code:
# Take credit amount values into a list
young = df['Credit_amount'].loc[df['Age_Group'] == 'Young'].values.tolist()
young_adults = df['Credit_amount'].loc[df['Age_Group'] == 'Young Adults'].values.tolist()
senior = df['Credit_amount'].loc[df['Age_Group'] == 'Senior'].values.tolist()
elder_credit = df['Credit_amount'].loc[df['Age_Group'] == 'Elder'].values.tolist()
# Create the box plots by age category
young_credit = go.Box(
y = young,
name = "Young",
jitter = 0.3,
pointpos = -1.8,
boxpoints = 'all',
marker = dict(
color = 'rgb(150, 198, 109)'),
line = dict(
color = 'rgb(111, 200, 37)')
)
young_adults_credit = go.Box(
y = young_adults,
name = "Young Adults",
jitter = 0.3,
pointpos = -1.8,
boxpoints = 'all',
marker = dict(
color = 'rgb(124, 236, 212)'),
line = dict(
color = 'rgb(38, 214, 177)')
)
senior_credit = go.Box(
y = senior,
name = "Seniors",
jitter = 0.3,
pointpos = -1.8,
boxpoints = 'all',
marker = dict(
color = 'rgb(241, 93, 93)'),
line = dict(
color = 'rgb(225, 44, 44)')
)
elder_credit = go.Box(
y = elder_credit,
name = "Elders",
jitter = 0.3,
pointpos = -1.8,
boxpoints = 'all',
marker = dict(
color = 'rgb(180, 121, 72)'),
line = dict(
color = 'rgb(115, 77, 46)')
)
data = [young_credit, young_adults_credit, senior_credit, elder_credit]
layout = dict(
title="Credit Amount by Age Group Segment",
xaxis = dict(title="Age Group"),
yaxis= dict(title="Credit Amount")
)
fig = dict(data=data, layout=layout)
iplot(fig, filename="Box Plot")
concerns the fragments marked in the picture below, I would like to remove those fragments from the chart and which lines of code I have to remove to achieve this goal.
I will be really thankfull for all clear answers because I can not find line of code to remove this fragments of plot.
Thank you so much!
If you Want to totally remove the points, you should remove parameters in each go.Box:
jitter = 0.3,
pointpos = -1.8,
boxpoints = 'all'
From plot.ly/python/box-plots/: With the points argument, display underlying data points with either all points (all), outliers only (outliers, default), or none of them (False).
Plot 1: boxpoints = False
Plot 2: boxpoints = 'all'
I got the same issue and can still not find the fix. The github issue is still open which Ahmed mentioned (https://github.com/plotly/plotly.js/issues/277).
Although, you can use a visible work around. It does not fix the problem! But for the vision it is fixed.
You van marker=dict(opacity=0) which makes the points invisible. When you hover over them, they are still there.
As far as I'm aware, I've copied the documentation exactly. I basically used the documentation code and tweaked it for my purposes. But when I run this bit of code, no hover feature with text appears on my plot.
#Initialize df
aviation_data = pd.DataFrame(columns=["Latitude","Longitude","Fatalities"])
aviation_data["Latitude"] = [40.53666,60.94444]
aviation_data["Longitude"] = [-81.955833,-159.620834]
aviation_data["Fatalities"] = [True,False]
#Initialize colorscale
scl = [[0,"rgb(216,15,15)"],[1,"rgb(5,10,172)"]]
#Initialize text data
text_df = "Fatal: " + aviation_data["Fatalities"].apply(lambda x: str(np.bool(x))) + '<br>' + \
"Latitude: " + aviation_data["Latitude"].apply(lambda x: str(x)) + '<br>' + \
"Longitude" + aviation_data["Longitude"].apply(lambda x: str(x))
#Initialize data
data = [ dict(
type = 'scattergeo',
locationmode = 'USA-states',
lon = aviation_data["Longitude"],
lat = aviation_data["Latitude"],
text = text_df,
mode = 'markers',
marker = dict(
size = 5,
opacity = 0.5,
reversescale=True,
autocolorscale=False,
symbol = 'circle',
line = dict(
width=1,
color='rgba(102, 102, 102)'
),
colorscale = scl,
cmin = 0,
color = aviation_data["Fatalities"].astype(int),
cmax = 1
))]
#Initialize layout
layout = dict(
title ='Aviation Incidents for the Years 2014-2016<br>\
(red indicates fatal incident, blue indicates non-fatal)',
geo = dict(
scope='usa',
projection=dict(type='albers usa'),
showland = True,
landcolor = "rgb(206, 206, 206)",
countrywidth = 0.5,
subunitwidth = 0.5
),
)
#Plot
fig = dict(data=data,layout=layout)
iplot(fig,validate=False)
Anyone know why my hover text isn't showing up?
In the last line of code you need to call this:
plotly.offline.plot(fig, validate=False)
Instead of:
iplot(fig, validate=False)
Also do not forget import plotly:
import plotly
Hope this will help
I'm trying to create a plotly graph with a Scatter and Graph elements. It all goes nicely, but one issue - the two Y axis don't align around 0.
I have tried playing with different attributes, such as 'mirror' and tick0, I also tried following the examples on plotly's site, but it's mostly multiple y-axis with the same graph type.
What can I do to fix this?
import utils
import pandas as pd
import plotly.plotly as py
import plotly.graph_objs as go
import plotly
pd_data ['dt'] = ... dates
pd_data['price'] = ... prices
pd_data['car'] = ... cars
price = go.Scatter(
x = pd_data['dt'],
y = pd_data['price'],
mode = 'lines',
name = 'Price',
xaxis = 'x',
yaxis='y1',
marker = dict(
color = utils.prep_color_string('orange'),
),
line = dict(
width = utils.line_width,
),
)
car = go.Bar(
x = pd_data['dt'],
y = pd_data['car'],
#mode = 'lines',
name = 'Cars',
xaxis = 'x',
yaxis='y2',
marker = dict(
color = utils.prep_color_string('light_green'),
),
#line = dict(
# width = utils.line_width,
#),
)
data = [price, car]
layout = dict(
title = 'Price/Car',
geo = dict(
showframe = True,
showcoastlines = True,
projection = dict(
type = 'Mercator'
)
),
yaxis=dict(
title = 'Price',
tickprefix = "$",
overlaying='y2',
anchor = 'x'
),
yaxis2=dict(
title = 'Car',
dtick = 1,
#tickprefix = "",
side = 'right',
anchor = 'x',
),
)
fig = dict( data=data, layout=layout)
div = plotly.offline.plot( fig, validate=False, output_type = 'file',filename='graph.html' ,auto_open = False)
I have been struggling with this as well. Exact same problem, but I am using R. The way I figured around it was to use the rangemode="tozero" for both the yaxis and yaxis2 layouts.
I think in your case, it would look like this:
layout = dict(
title = 'Price/Car',
geo = dict(
showframe = True,
showcoastlines = True,
projection = dict(
type = 'Mercator'
)
),
yaxis=dict(
title = 'Price',
tickprefix = "$",
overlaying='y2',
anchor = 'x',
rangemode='tozero'
),
yaxis2=dict(
title = 'Car',
dtick = 1,
#tickprefix = "",
side = 'right',
anchor = 'x',
rangemode = 'tozero'
),
)
Let me know if that works for you.