Some bars are missing from the plotly dash plot randomly - plotly-dash

I am creating a dashboard using Plotly Dash which contains plots with a bar and a line graph on the common x axis. The code is working fine when I run it, however when I am selecting different options from the dropdown to change the graph, some bars go missing from the plot randomly for some options.
Here is an example that’s working perfectly fine.perfectly fine image
And here is an example where a bar goes missing from the plot when i select a different option from dropdown.
image with missing bar
I am not sure what’s wrong. I have checked if the data is missing for the missing bar but it’s there and when I am hovering over the missing bar area in the plot, it is also showing me the value there but not the bar. For reference, here is my code…
trace1 = go.Scatter(
mode='lines+markers+text',
x = df1['Date'],
y = df1['AVG'],
name="Avg time(mins)",
text=df1['AVG'],
textposition='bottom right',
textfont_color='black',
marker_color='blue',
opacity=1
)
trace2 = go.Bar(
x = df1['Date'],
y = df1['Id_Count'],
name="Count",
ids=df1['Id_Count'],
text=df1['Id_Count'],
textposition='inside',
insidetextfont_color='#45FC03',
hoverinfo='x+y',
yaxis='y2',
marker_color ='#180702',
marker_line_width=1.5,
marker_line_color='black',
opacity=0.72
)
data1 = [trace1, trace2]
layout1 = go.Layout(
title_text='Day wise stats',
title_font_color='#45FC03',
width=1300,
height=400,
yaxis=dict(
side = 'right'
),
yaxis2=dict(
overlaying='y',
anchor='y3',
)
)
fig1 = go.Figure(data=data1, layout=layout1)
fig1.update_layout(template='plotly_dark',
plot_bgcolor='#F0E199', paper_bgcolor='#282522', margin_l=50, margin_t=80, margin_b=60)
fig1.update_xaxes(showgrid=False, zeroline=False)
fig1.update_yaxes(showgrid=False, zeroline=False)
Please, any help would be appreciated for a solution to this problem.

contents of bars is based on data in dataframe
below code shows bar disappears if underlying dataframe has NaN as value
import pandas as pd
import numpy as np
import plotly.graph_objects as go
df1 = pd.DataFrame({"Date":pd.date_range("28-sep-2021", freq="D", periods=7), "AVG":np.round(np.random.uniform(2,5,7),2), "Id_Count":np.random.randint(2000,3000,7)})
def graph(df1):
trace1 = go.Scatter(
mode='lines+markers+text',
x = df1['Date'],
y = df1['AVG'],
name="Avg time(mins)",
text=df1['AVG'],
textposition='bottom right',
textfont_color='black',
marker_color='blue',
opacity=1
)
trace2 = go.Bar(
x = df1['Date'],
y = df1['Id_Count'],
name="Count",
ids=df1['Id_Count'],
text=df1['Id_Count'],
textposition='inside',
insidetextfont_color='#45FC03',
hoverinfo='x+y',
yaxis='y2',
marker_color ='#180702',
marker_line_width=1.5,
marker_line_color='black',
opacity=0.72
)
data1 = [trace1, trace2]
layout1 = go.Layout(
title_text='Day wise stats',
title_font_color='#45FC03',
width=800,
height=400,
yaxis=dict(
side = 'right'
),
yaxis2=dict(
overlaying='y',
anchor='y3',
)
)
fig1 = go.Figure(data=data1, layout=layout1)
fig1.update_layout(template='plotly_dark',
plot_bgcolor='#F0E199', paper_bgcolor='#282522', margin_l=50, margin_t=80, margin_b=60)
fig1.update_xaxes(showgrid=False, zeroline=False)
fig1.update_yaxes(showgrid=False, zeroline=False)
return fig1
graph(df1).show()
df1.loc[df1.sample(1).index, "Id_Count"] = np.nan
graph(df1).show()

Related

Layout Parser: lp.draw_box not working in for loop

I am trying to visualize pages after passing through layout parser using lp.draw_box. It works fine for a single image, but if I run through a for loop and try for each image at once from a set of images, it doesn't print anything. Could someone please help me here? THanks
Code:
from pdf2image import convert_from_path, convert_from_bytes
import cv2, time
start = time.time()
images = convert_from_path(f"/content/neft-system-faq.pdf")
page_layout_map = {}
for idx, image in enumerate(images):
image.save('out.png', 'PNG')
image = cv2.imread("out.png")
image = image[..., ::-1]
layout = model.detect(image)
lp.draw_box(image, layout,None,show_element_id=True)
text_blocks = lp.Layout([b for b in layout])
print(text_blocks)
block_test = get_coordinates(text_blocks)
result_arr = layout_map_processor(block_test)
page_layout_map[idx] = result_arr
print(time.time()-start)

Is it possible to arrange graphs and filters in an R plot output?

I have created a small dashboard using bscols( from the crosstalkpackage. It consists of plotly graphs and their respective filter_checkboxes.
It looks pretty messy now, as the filters are not vertically aligned with their corresponding plots.
HTML_graphic
As indicated, I would like the first two checkbox sets to appear next to the second line graph (nothing to appear next to the first line graph); and the second two checkbox sets to appear next to the third line graph.
Also, I would like to create some vertical space between the three elements, as indicated by the brown and black horizontal lines.
The best solution would be to set the height of the html elements inside the bscols() command. Because in the future, I would like to programmatically save multiple of these outputs using htmltools::save_html.
The next best would be to have the output of that command somehow converted to html and add html code like line breaks or heights.
Neither I know how to do.
I came across this related question but it is unanswered: Arrange crosstalk graphs via bscols
Any suggestions on how to solve my problem?
My code
{r 002_Auto App Doc Vol_Invoice group delta plot - plot code, echo = FALSE}
# Setup of the legend for invoice plot
invoice_plot_legend <- list(
font = list(
family = "sans-serif",
size = 12,
color = "#000"),
title = list(text="<b> Delta previous month by division </b>"),
bgcolor = "#E2E2E2",
bordercolor = "#FFFFFF",
borderwidth = 2,
layout.legend = "constant",
traceorder = "grouped")
# The Shared Data format is needed for crosstalk to be able to filter the dataset upon clicking the checkboxes (division filters):
shared_invoice <- SharedData$new(Auto_App_Doc_Vol_invoiceg_plotting_tibble)
shared_invoice_KPI <- SharedData$new(Auto_App_Doc_Vol_KPI)
shared_abs <- SharedData$new(Auto_App_Doc_Vol_plotting_tibble_diff_abs)
# Setup of a bscols html widget; widths determines the widths of the input lists (here, 2: the filters, 10: the plot and legend)
# Overall KPI and invoice group plot
library(htmlwidgets)
crosstalk::bscols(
widths = c(2, 10),
list(
crosstalk::filter_checkbox("Division",
label = "Division",
sharedData = shared_invoice,
group = ~Division),
crosstalk::filter_checkbox("Rechnungsgruppe",
label = "Invoice group",
sharedData = shared_invoice,
group = ~Rechnungsgruppe),
crosstalk::filter_checkbox("Rechnungsgruppe",
label = "Invoice group",
sharedData = shared_abs,
group = ~Rechnungsgruppe),
crosstalk::filter_checkbox("Division",
label = "Division",
sharedData = shared_abs,
group = ~Division)
)
,
list(
plot_ly(data = shared_invoice_KPI, x = ~Freigabedatum_REAL_YM, y = ~KPI_current_month, meta = ~Division,
type = "scatter",
mode = "lines+text",
text = ~KPI_current_month,
textposition='top center',
hovertemplate = "%{meta}",
color = ~Diff_KPI_pp)
%>%
layout(legend = invoice_plot_legend,
title = "Automatically Approved Document Volume",
xaxis = list(title = 'Release date'),
yaxis = list(title = '%'))
,
plot_ly(data = shared_invoice, x = ~Freigabedatum_REAL_YM, y = ~n,
type = "scatter",
mode = "lines",
text = ~Rechnungsgruppe_effort,
hoverinfo = "y+text",
color = ~Difference_inline
)
%>%
layout(legend = invoice_plot_legend,
title = " ",
xaxis = list(title = 'Release date'),
yaxis = list(title = '# of Approved Documents'))
,
plot_ly(data = shared_abs, x = ~Freigabedatum_REAL_YM, y = ~n,
type = "scatter",
mode = "lines",
text = ~Lieferantenname,
hoverinfo = "y+text",
color = ~Lieferantenname_text
)
%>%
layout(legend = vendor_plot_legend,
title = "by vendor absolute delta previous month all documents",
xaxis = list(title = 'Release date'),
yaxis = list(title = '# of Approved Documents w/ & w/o effort')
)
)
)
Thank you so much!

Plotly, Changing the hover text

I am trying to change the hover text in plotly.
As an example there is
import plotly.graph_objects as go
fig = go.Figure(go.Scatter(
x = [1,2,3,4,5],
y = [2.02825,1.63728,6.83839,4.8485,4.73463],
hovertemplate =
'<i>Price</i>: $%{y:.2f}'+
'<br><b>X</b>: %{x}<br>'+
'<b>%{text}</b>',
text = ['Custom text {}'.format(i + 1) for i in range(5)],
showlegend = False))
fig.add_trace(go.Scatter(
x = [1,2,3,4,5],
y = [3.02825,2.63728,4.83839,3.8485,1.73463],
hovertemplate = 'Price: %{y:$.2f}<extra></extra>',
showlegend = False))
fig.update_layout(
hoverlabel_align = 'right',
title = "Set hover text with hovertemplate")
fig.show()
Can you see the part in blue where it says "trace 0". Where does that come from?
If you hover in the red curve you will notice that something similar does not appear.
I want to reproduce this, so I want to understand where that is coming from
You can enable/disable the trace0, trace1,... text for each set of points by removing/adding the <extra></extra> tag. The documentation for hover text customization can be found here.
To make trace1 appear on your second set of points, remove the <extra></extra> tag.
import plotly.graph_objects as go
fig = go.Figure(go.Scatter(
x = [1,2,3,4,5],
y = [2.02825,1.63728,6.83839,4.8485,4.73463],
hovertemplate =
'<i>Price</i>: $%{y:.2f}'+
'<br><b>X</b>: %{x}<br>'+
'<b>%{text}</b>',
text = ['Custom text {}'.format(i + 1) for i in range(5)],
showlegend = False))
## Remove the extra tag
fig.add_trace(go.Scatter(
x = [1,2,3,4,5],
y = [3.02825,2.63728,4.83839,3.8485,1.73463],
hovertemplate = 'Price: %{y:$.2f}',
showlegend = False))
fig.update_layout(
hoverlabel_align = 'right',
title = "Set hover text with hovertemplate")
fig.show()

How to effectively adjust graph margin or padding in dash plotly

I have plotted two graphs using plotly dash. But when the y-axis / x-axis tick size is more it gets cut off.
Y-axis :
Code :
data = [go.Scatter(x = df[df['S2PName-Category']==category]['S2BillDate'],
y = df[df['S2PName-Category']==category]['totSale'],
mode = 'markers+lines',
name = category) for category in df['S2PName-Category'].unique()]
layout = go.Layout(title='Category Trend',
xaxis = dict(title = 'Time Frame', tickformat = '%d-%b-%y'),
yaxis = dict(tickprefix= '₹', tickformat=',.2f',type='log'),
hovermode = 'closest',
plot_bgcolor = colors['background'],
paper_bgcolor = colors['background'],
font = dict(color = colors['text'])
)
X-Axis :
Code :
data = [go.Scatter(x = df[df['S2PName']==item]['S2BillDate'],
y = df[df['S2PName']==item]['totSale'],
mode = 'markers+lines',
name = item) for item in items]
layout = go.Layout(title='Category Trend',
xaxis = dict(title = 'Time Frame' , tickformat = '%d-%b'),
yaxis = dict(tickprefix= '₹', tickformat=',.2f',type='log',autorange = True),
hovermode = 'closest',
plot_bgcolor = colors['background'],
paper_bgcolor = colors['background'],
font = dict(color = colors['text'])
)
In the above 2 graphs , as the length of the tick value increases, it gets cut off . Is there a better way to handle this ?
Credit for #Flavia Giammarino in comments for the reference to the docs. I'm posting the answer for completeness.
https://plotly.com/python/setting-graph-size/
From that link the example below shows how to set margin:
fig.update_layout(
margin=dict(l=20, r=20, t=20, b=20),
)
Where l r t b correspond to left, right, top, bottom.
I had a similar problem with some Dash/Plotly charts and long y axis labels being truncated or hidden. There didn't seem to be much information or documentation on this issue, so it took a while to solve.
Solution: add this code to the layout settings to prevent truncation of the y axes labels:
fig.update_layout(
yaxis=dict(
automargin=True
)
)
or you can update the yaxes setting specifically:
fig.update_yaxes(automargin=True)
Update: I tried another version of Plotly (5.10 or above) which mentions setting the automargin setting to any combination of automargin=['left+top+right+bottom'] with similar results. This still seems a bit unstable and doesn't solve all possible scenarios or corner cases, but works fine in most cases, especially when the browser window is maximized.

Bokeh: Link Hover tooltips geometrically to subplots

I have multiple categorical heatmap plots that are in a single display that have identical shapes and x,y coordinates. When hovering on any of the subplots I would like the inspection on one plot to trigger a new inspection on all other plots in the grid and display multiple tooltips simultaneously.
I have researched this topic and found similar posts such as:
Bokeh: Synchronizing hover tooltips in linked plots
Takeaway from link above: There are 2 suggested answers to this question, which attempt to mimic hover tooltips with text glyphs, however these implementations are not successful when I copy and run the code on my own computer (the graphs display correctly but the hover text glyphs don't appear). I assume this could be because of Bokeh API updates, but I am unsure. My reputation doesn't allow comments or I'd address this issue there.
Coordinate tooltips across multiple plots #1547
Takeaway from link above: There is no reproducible data so I am not able to recreate the plot listed here, however bryevdv summarizes what I am trying to do quite efficiently which I'll quote below:
Link on geometry. You might want the geometry of the inspection on one plot to trigger a completely new inspection (using that same geometry) on another plot. So if the cursor is at (10.5, 7) on one plot, then the additional plots do a hit test at (10.5, 7) and if there are glyphs that have any hovers a that point, then a hover gets drawn there.
I have created some generalized data to illustrate my problem:
from bokeh.io import show, output_notebook
from bokeh.layouts import gridplot
from bokeh.models import LinearColorMapper, HoverTool
from bokeh.plotting import figure, show, output_file
from bokeh.transform import transform
import numpy as np
import pandas as pd
data1 = [['A','A',100], ['A','B',175], ['B','A',75], ['B','B',200]]
data2 = [['A','A',25], ['A','B',100], ['B','A',50], ['B','B',75]]
data3 = [['A','A',150], ['A','B',75], ['B','A',25], ['B','B',125]]
df1 = pd.DataFrame(data1, columns = ['Left','Right','Value'])
df2 = pd.DataFrame(data2, columns = ['Left','Right','Value'])
df3 = pd.DataFrame(data3, columns = ['Left','Right','Value'])
def heatmap(df, title):
letters = ['A','B']
mapper = LinearColorMapper(palette=['#225ea8', '#41b6c4', '#a1dab4', '#ffffcc'], low=0, high=200)
TOOLS = 'reset'
p = figure(plot_width=255, plot_height=250, title=title,
x_range=letters,
y_range=list(reversed(letters)), x_axis_location='above',
tools=TOOLS, toolbar_location='below')
p.grid.grid_line_color = None
p.grid.grid_line_width = 0.5
p.axis.axis_line_color = None
p.axis.major_tick_line_color = None
p.axis.major_label_text_font_size = '9pt'
p.axis.major_label_standoff = 0
p.xaxis.major_label_orientation = 0
hover = HoverTool()
p.rect(x='Right', y='Left', width=1, height=1, line_color=None, source=df,
fill_color={'field': 'Value', 'transform': mapper})
hover.tooltips = [('Group','#Left #Right'), ('Value','#Value')]
p.tools.append(hover)
return p
output_notebook()
p1 = heatmap(df1, 'Plot 1')
p2 = heatmap(df2, 'Plot 2')
p3 = heatmap(df3, 'Plot 3')
grid = gridplot([[p1,p2,p3]])
show(grid)
Output:
My goal is to be able to observe the values across multiple plots at one time without having to be directed to another page or source, so I am open to alternative ways of doing this that doesn't involve hover tooltips. Thanks!