I am trying to change the figure size (height and width) of the figure that I called using plotly cufflinks for pandas. I know that I could separately Layout from plotly.graph_objs and then give the height and width command. However, is there a way I could control the font and/or figure parameters using cufflinks.
I am plotting the Reasons for delisting of stocks on X axis and their count on Y.
Here is my code
grped = d_list_data.groupby(['Reasons Short']).size()
import cufflinks as cf
grped.iplot(kind = 'bar',
xTitle = 'Reasons for Delisting',
yTitle= 'Count',
title= 'Delisting Reasons since 2001',
theme = 'polar',
)
Define a Layout with your desired height and width properties and use it inside the cufflinks iplot call.
layout1 = cf.Layout(
height=300,
width=200
)
grped.iplot(kind = 'bar',
xTitle = 'Reasons for Delisting',
yTitle= 'Count',
title= 'Delisting Reasons since 2001',
theme = 'polar',
layout=layout1
)
I tried this within Jupyterlab and using the above approach was getting error:
AttributeError: 'Layout' object has no attribute 'get'
Converting the layout to a dict as suggested here (https://community.plot.ly/t/cant-edit-layouts-with-cufflinks/15038/4) made it work.
So, the above becomes:
layout1 = cf.Layout(
height=300,
width=200
)
grped.iplot(kind = 'bar',
xTitle = 'Reasons for Delisting',
yTitle= 'Count',
title= 'Delisting Reasons since 2001',
theme = 'polar',
layout=layout1.to_plotly_json()
)
The iplot method has the following parameter that controls the dimension of the chart: dimensions : tuple(width,height). So you could try:
grped.iplot(kind = 'bar',
xTitle = 'Reasons for Delisting',
yTitle= 'Count',
title= 'Delisting Reasons since 2001',
theme = 'polar',
dimensions =(300,200)
)
Related
I want to include a line chart (constructed with matplotlib) in an interactive dashboard. My graph describes the evolution for one year of the frequency of the word "France" in 7 media for Central Africa. The database is called: "df_france_pivot".
What I've seen so far is that first of all I have to transform my plot into an object with the go.figure function. So I tried this code:
`app = dash.Dash()
def update_graph():
plt.style.use('seaborn-darkgrid')
fig, ax = plt.subplots()
ax.set_prop_cycle(color=['304558', 'FE9235', '526683', 'FE574B', 'FFD104', '6BDF9C'])
num=0
for column in df_france_pivot.drop('month_year', axis=1):
num+=1
plt.plot(df_france_pivot['month_year'], df_france_pivot[column], marker='',
linewidth=1, alpha=0.9, label=column)
plt.xticks(rotation=45)
plt.legend(loc=0, prop={'size': 9},bbox_to_anchor=(1.05, 1.0), title='Media in South Africa')
plt.title("Frequency of the word 'France' in the media ", loc='left', fontsize=12, fontweight=0, color='orange')
plt.xlabel("Time")
plt.ylabel("Percentage")
figure = go.Figure(fig)
return figure
app.layout = html.Div(id = 'parent', children = [
html.H1(id = 'H1', children = 'Styling using html components', style = {'textAlign':'center',\
'marginTop':40,'marginBottom':40}),
dcc.Graph(id = 'line_plot', figure = update_graph())
]
)`
When running it I got this response: Output exceeds the size limit. Open the full output data in a text editor. Is it because my linechart is more complex i.e. with 7 lines?
Thank you in advance!
I'd like to fill the charts with selectors like the example below. Any tips on how to get this to work in a faceted chart?
np.random.seed(42)
source = pd.DataFrame(np.cumsum(np.random.rand(8, 4), 0).round(2),
columns=['A', 'B', 'C', 'D'], index=pd.RangeIndex(8, name='x'))
source = source.reset_index().melt('x', var_name='category', value_name='y')
xRange= pd.DataFrame(np.linspace(min(source['x']), max(source['x']), num=100), columns=['x'])
pts = alt.selection_multi(fields=['x'], nearest=True, on='click',empty='none')
# The basic line
main = alt.Chart(source).mark_line(interpolate='basis').encode(
x='x:Q',
y='y:Q',
).transform_filter(
alt.FieldEqualPredicate(field='category', equal='A')
)
line = alt.Chart(source).mark_line(color='Maroon').encode(
x='x:Q',
y='y:Q',
).transform_filter(
alt.FieldEqualPredicate(field='category', equal='B')
)
# Transparent selectors across the chart. This is what tells us
# the x-value of the cursor
selectors = alt.Chart(xRange).mark_rule(size=2).encode(
x='x:Q',
#y='y:Q',
#opacity=alt.value(0.4),
opacity = alt.condition(pts, alt.value(1.0), alt.value(0.2))
).add_selection(pts)
position = alt.Chart(xRange).mark_text(
align='right', dy=140, dx=-8, fontSize=14).encode(
x=alt.X('x'),
text=alt.Text('x',format='.1f')
).transform_filter(pts)
alt.vconcat(
main + selectors + position,
line + selectors + position
)
But ideally using facet, however i have not found a way around that you can only use a single DataFrame/source. Is there a way to use alt.sequence of impute to generate additional points on the x-axis?
pts = alt.selection_multi(fields=['x'], nearest=True, on='click',empty='none')
# The basic line
line = alt.Chart().mark_line(interpolate='basis').encode(
x='x:Q',
y='y:Q',
)
# Transparent rules across the chart.
rules = alt.Chart().mark_rule(size=2).encode(
x='x:Q',
opacity = alt.condition(pts, alt.value(1.0), alt.value(0.3))
).add_selection(pts)
text = alt.Chart().mark_text(
align='right', dy=140, dx=-8, fontSize=14).encode(
x=alt.X('x'),
text=alt.Text('x',format='.1f')
).transform_filter(pts)
alt.layer(line, rules, text, data=source).facet(
'category:N',
columns=2
)
You can use the sequence generator. It is almost the same to what you had already:
import numpy as np
import pandas as pd
import altair as alt
np.random.seed(42)
source = pd.DataFrame(np.cumsum(np.random.rand(8, 4), 0).round(2),
columns=['A', 'B', 'C', 'D'], index=pd.RangeIndex(8, name='x'))
source = source.reset_index().melt('x', var_name='category', value_name='y')
# xRange= pd.DataFrame(np.linspace(min(source['x']), max(source['x']), num=100), columns=['x'])
xRange = alt.sequence(0, 7.1, 0.1, as_='x')
pts = alt.selection_multi(fields=['x'], nearest=True, on='mouseover',empty='none')
# The basic line
line = alt.Chart().mark_line(interpolate='linear').encode(
x='x:Q',
y='y:Q',
)
# Transparent rules across the chart.
rules = alt.Chart(xRange).mark_rule(size=2).encode(
x='x:Q',
opacity = alt.condition(pts, alt.value(1.0), alt.value(0.3))
).add_selection(pts)
text = alt.Chart(xRange).mark_text(
align='right', dy=140, dx=-8, fontSize=14).encode(
x=alt.X('x:Q'),
text=alt.Text('x:Q',format='.1f')
).transform_filter(pts)
alt.layer(line, rules, text, data=source).facet(
'category:N',
columns=2
)
I have the following code to generate two bar charts. The first one is a "Central" scenario that needs to be always visible. The second represents multiple stress scenarios with values depending on two sliders.
My problem is to concat the two charts, letting spaces between the two series and making them visible in any cases (like a grouped bar chart).
Here is my code :
import altair as alt
from vega_datasets import data
pvfp=Res.loc[(Res.Item=="PVFP")&(Res.annee>0)]
base = alt.Chart(pvfp, width=500, height=300).mark_bar(color="Green").encode(
x=alt.X('annee:Q'),
y='valeur:Q',
tooltip="valeur:Q"
)
central = alt.Chart(pvfp.loc[(Res.TS=='Central')&(Res.TRA=='Central')], width=500, height=300).mark_bar().encode(
x=alt.X('annee:Q'),
y='valeur:Q',
tooltip="valeur:Q"
)
# A slider filter
TRA_slider = alt.binding_range(min=-40, max=20, step=10,name="Sensi TRA :")
TS_slider = alt.binding_range(min=-20, max=20, step=5,name="Sensi TS : ")
slider1 = alt.selection_single(bind=TRA_slider, fields=['TRA2'],init={'TRA2': 0})
slider2 = alt.selection_single(bind=TS_slider, fields=['TS2'],init={'TS2': 0})
filter_TRA = base.add_selection(
slider1,slider2
).transform_filter(
slider1&slider2
).properties(title="Sensi_TRA")
central + filter_TRA
And a view of the chart I obtain for now :
If you have any idea of a way to do that, I would be very grateful.
UPDATE :
Here is a reproductible example of the same problem.
import altair as alt
import pandas as pd
from vega_datasets import data
dataset = data.population.url
source=pd.read_json(dataset)
source2=df.loc[df.year==1900]
pink_blue = alt.Scale(domain=('Male', 'Female'),
range=["steelblue", "salmon"])
slider = alt.binding_range(min=1900, max=2000, step=10)
select_year = alt.selection_single(name="year", fields=['year'],
bind=slider, init={'year': 2000})
chart1 = alt.Chart(source).mark_bar().encode(
x=alt.X('age:O', title=None),
y=alt.Y('people:Q', scale=alt.Scale(domain=(0, 12000000))),
).properties(
width=300
).add_selection(
select_year
).transform_filter(
select_year
)
chart2 = alt.Chart(source2).mark_bar(color="green").encode(
x=alt.X('age:O', title=None),
y=alt.Y('people:Q', scale=alt.Scale(domain=(0, 12000000))),
)
chart1+chart2
As described, what I would like is to find a way to separate the two series and obtain an output like in the example mentioned by #joelostblom
Hope it's more clear
You can do this with a combination of bandPaddingInner and xOffset. For example:
import altair as alt
import pandas as pd
from vega_datasets import data
dataset = data.population.url
source=pd.read_json(dataset)
source2=source.loc[source.year==1900]
pink_blue = alt.Scale(domain=('Male', 'Female'),
range=["steelblue", "salmon"])
slider = alt.binding_range(min=1900, max=2000, step=10)
select_year = alt.selection_single(name="year", fields=['year'],
bind=slider, init={'year': 2000})
chart1 = alt.Chart(source).mark_bar(
xOffset=-3
).encode(
x=alt.X('age:O', title=None),
y=alt.Y('people:Q', scale=alt.Scale(domain=(0, 12000000))),
).properties(
width=300
).add_selection(
select_year
).transform_filter(
select_year
)
chart2 = alt.Chart(source2).mark_bar(
xOffset=5,
color="green",
).encode(
x=alt.X('age:O', title=None),
y=alt.Y('people:Q', scale=alt.Scale(domain=(0, 12000000))),
)
(chart1+chart2).configure_scale(bandPaddingInner=0.6)
I am trying to display the widgets of a HoloViews dynamic plot (Select, Slider, etc.) over the plot. All I can find is the widget_location argument which takes the location relative to the plot (‘left’ , ‘right’, …). But I want it to be placed over the plot, not next to it. I was wondering if there is a way for doing this?
P.S. for instance there is opts(colorbar_opts={'location':(float,float)}) which can be used to place the colorbar where you want. It would be very useful to have a similar option for widgets.
OK, I found the solution! I have to use custom CSS. The code below shows how to do it.
import holoviews as hv
import panel as pn
pn.extension('ace')
hv.extension("bokeh")
plots = {}
for i in range(5,10):
data = {
"x": list(range(0,i)), "y": [i]*i
}
plots[i]=hv.Curve(data).opts(width=500)
hvmap = hv.HoloMap(plots)
left_pos = pn.widgets.IntSlider(value=5, step=1, start=-1000, end=5, name="x")
top_pos = pn.widgets.IntSlider(value=5, step=1, start=5, end=200, name="y")
style = pn.pane.HTML(height=0, width=0, sizing_mode="fixed", margin=0)
css = pn.widgets.Ace(height=150)
#pn.depends(left_pos=left_pos, top_pos=top_pos, watch=True)
def _update_css(left_pos, top_pos):
value = f"""
.bk.panel-widget-box {{
left: {left_pos}px !important;
top: {top_pos}px !important;
}}
"""
css.value = value
style.object = "<style>" + value + "</style>"
pn.Column("""# How to overlay widgets on HoloViews Map?
We will be using css to overlay and Panel to create the this tool""",
hvmap,
"## Settings",
left_pos,
top_pos,
css,
style,
).servable()
All credits goes to Marc Skov Madsen. Original answer here
I would like to plot a ggplot2 image using ggplotly
What I am trying to do is to initially plot rectangles of grey fill without any aesthetic mapping, and then in a second step to plot tiles and change colors based on aesthetics. My code is working when I use ggplot but crashes when I try to use ggplotly to transform my graph into interactive
Here is a sample code
library(ggplot2)
library(data.table)
library(plotly)
library(dplyr)
x = rep(c("1", "2", "3"), 3)
y = rep(c("K", "B","A"), each=3)
z = sample(c(NA,"A","L"), 9,replace = TRUE)
df <- data.table(x,y,z)
p<-ggplot(df)+
geom_tile(aes(x=x,y=y),width=0.9,height=0.9,fill="grey")
p<-p+geom_tile(data=filter(df,z=="A"),aes(x=x,y=y,fill=z),width=0.9,height=0.9)
p
But when I type this
ggplotly(p)
I get the following error
Error in [.data.frame(g, , c("fill_plotlyDomain", "fill")) :
undefined columns selected
The versions I use are
> packageVersion("plotly")
1 ‘4.7.1
packageVersion("ggplot2")
1 ‘2.2.1.9000’
##########Edited example for Arthur
p<-ggplot(df)+
geom_tile(aes(x=x,y=y,fill="G"),width=0.9,height=0.9)
p<- p+geom_tile(data=filter(df,z=="A"),aes(x=x,y=y,fill=z),width=0.9,height=0.9)
p<-p+ scale_fill_manual(
guide = guide_legend(title = "test",
override.aes = list(
fill =c("red","white") )
),
values = c("red","grey"),
labels=c("A",""))
p
This works
but ggplotly(p) adds the grey bar labeled G in the legend
The output of the ggplotly function is a list with the plotly class. It gets printed as Plotly graph but you can still work with it as a list. Moreover, the documentation indicates that modifying the list makes it possible to clear all or part of the legend. One only has to understand how the data is structured.
p<-ggplot(df)+
geom_tile(aes(x=x,y=y,fill=z),width=0.9,height=0.9)+
scale_fill_manual(values = c(L='grey', A='red'), na.value='grey')
p2 <- ggplotly(p)
str(p2)
The global legend is here in p2$x$layout$showlegend and setting this to false displays no legend at all.
The group-specific legend appears at each of the 9 p2$x$data elements each time in an other showlegend attribute. Only 3 of them are set to TRUE, corresponding to the 3 keys in the legend. The following loop thus clears all the undesired labels:
for(i in seq_along(p2$x$data)){
if(p2$x$data[[i]]$legendgroup!='A'){
p2$x$data[[i]]$showlegend <- FALSE
}
}
Voilà!
This works here:
ggplot(df)+
geom_tile(aes(x=x,y=y,fill=z),width=0.9,height=0.9)+
scale_fill_manual(values = c(L='grey', A='red'), na.value='grey')
ggplotly(p)
I guess your problem comes from the use of 2 different data sources, df and filter(df,z=="A"), with columns with the same name.
[Note this is not an Answer Yet]
(Putting for reference, as it is beyond the limits for comments.)
The problem is rather complicated.
I just finished debugging the code of plotly. It seems like it's occurring here.
I have opened an issue in GitHub
Here is the minimal code for the reproduction of the problem.
library(ggplot2)
set.seed(1503)
df <- data.frame(x = rep(1:3, 3),
y = rep(1:3, 3),
z = sample(c("A","B"), 9,replace = TRUE),
stringsAsFactors = F)
p1 <- ggplot(df)+
geom_tile(aes(x=x,y=y, fill="grey"), color = "black")
p2 <- ggplot(df)+
geom_tile(aes(x=x,y=y),fill="grey", color = "black")
class(plotly::ggplotly(p1))
#> [1] "plotly" "htmlwidget"
class(plotly::ggplotly(p2))
#> Error in `[.data.frame`(g, , c("fill_plotlyDomain", "fill")): undefined columns selected