Streamlit conditional formatting for rows in a table - ag-grid

I'm trying to add conditional formatting to table rows in my streamlit app. Using streamlit-aggrid package for it, for now, I found a way to format the table only per-column, for example:
gb = GridOptionBuilder.from_dataframe(mydf)
jscode = JsCode("""
function(params) {
if (params.value > 70) {
return {
'color': 'white'
'backgroundColor': '#fa7e74'
}
} else {
return {
'color': 'black'
'backgroundColor': '#cdf6df'
}
}
};
""")
gb.configure_columns(mydf.columns[col_list], cellStyle=jscode, editable=True)
gridOptions = gb.build()
AgGrid(mydf,gridOptions=gridOptions,allow_unsafe_jscode=True)
I want to get something like this:

I found this article on medium how to make it with Seaborn:
# Set CSS properties for th elements in dataframe
th_props = [
('font-size', '15px'),
('text-align', 'center'),
('font-weight', 'bold'),
('color', '#6d6d6d'),
('backgroud-color', '#f7ffff')
]
#Set table styles
styles = [
dict(selector="th", props=th_props)
]
#Set colormap equal to seaborn light green color palette
cm = sns.light_palette('green', as_cmap=True)
table_to_render = (mydf.style
.background_gradient(cmap=cm, axis=1)
.set_caption('This is custom caption.')
.format(na_rep = 'No data', precision=2, thousands=',')
.highlight_null(null_color='white')
.set_table_styles(styles))
st.table(table_to_render)

Related

Plotly Dash - Python - Issue with callback function

Please bare with my limited experience in programming. At least, I will elaborate.
My task is to create a Dropdown for a number of launch sites, and then plot the success rate in a pie chart. The user can also select a range of payloads with a RangeSlider, that will be used to create a scatter plot.
This is how the result should look like:
enter image description here
Here is the code:
from dash import Dash, dcc, html, Input, Output
import pandas as pd
import plotly.express as px
import plotly.graph_objects as go
URL = 'https://cf-courses-data.s3.us.cloud-object-storage.appdomain.cloud/IBM-DS0321EN-SkillsNetwork/datasets/spacex_launch_geo.csv'
df_spacex = pd.read_csv(URL)
df_spacex.head()
# dropdown menu to choose from the various sites:
app = Dash(__name__)
app.layout = html.Div(children = [
html.Div([
html.H1('SpaceX Launch Records Dashboard',
style = {'textAlign': 'center',
'color': 'black',
'font-size': 24}
),
html.Label('Dropdown:',
style = {'color': 'black',
'font-size': 18}
),
dcc.Dropdown(id = 'site-dropdown',
options = [{'label': 'All Sites', 'value': 'ALL'},
{'label': 'CCAFS SCL-40', 'value': 'CCAFS SLC-40'},
{'label': 'CCAFS LC-40', 'value': 'CCAFS LC-40'},
{'label': 'VAFB SLC-4E', 'value': 'VAFB SLC-4E'},
{'label': 'KSC LC-39A', 'value': 'KSC LC-39A'}],
value = 'ALL',
placeholder = 'Select a site',
searchable = True,
style = {'width': '80%', 'height': '3px',
'textAlign': 'left', 'font-size': '16px'}
),
]),
html.Div([
html.Br(),
html.Br(),
dcc.Graph(id = 'success-pie-chart'),
html.Br(),
html.Label('Payload range slider (kg):',
style = {'color': 'black',
'font-size': 18}
),
dcc.RangeSlider(id = 'payload-slider',
min = df_spacex['Payload Mass (kg)'].min(),
max = df_spacex['Payload Mass (kg)'].max(),
step = 1000,
marks = {0: '0',
100: '100'},
value = [2000, 8000]
),
html.Br(),
dcc.Graph(id = 'success-payload-scatter-chart')
])
])
# function decorator to specify function input and output
#app.callback(Output('success-pie-chart', 'figure'),
Output('success-payload-scatter-chart', 'figure'),
Input('site-dropdown', 'value'),
Input('payload-slider', 'value'))
def get_pie_chart(entered_site, payload):
if entered_site == 'ALL':
fig = px.pie(df_spacex, values = 'class', names = 'Launch Site',
title = 'Successful Launch Distribution by Site')
else:
# choose the rows that have the same launch site as the one entered
df_filtered = df_spacex.loc[df_spacex['Launch Site'] == entered_site]
fig = px.pie(df_filtered, names = 'class',
title = 'Launch Distribution for ' + entered_site)
return fig
def get_scatter_chart(entered_site, payload):
# expand equals True to return a data frame
# with seperated strings in different columns
df_split = df_spacex['Booster Version'].str.split(' ', expand = True)
# save the modified data frame
df_mod = df_spacex.drop(columns = ['Booster Version'], inplace = False)
df_mod['Booster Version'] = df_split[1]
print(payload)
# based on the input payload range choose the corresponding rows
df_mod = df_mod.loc[(df_mod['Payload Mass (kg)'] >= payload[0]) & (df_mod['Payload Mass (kg)'] <= payload[1])]
if entered_site == 'ALL':
fig = px.scatter(df_mod,
x = 'Payload Mass (kg)',
y = 'class',
color = 'Booster Version',
hover_data = ['Booster Version'])
else:
df_filtered = df_mod.loc[df_mod['Launch Site'] == entered_site]
fig = px.scatter(df_filtered,
x = 'Payload Mass (kg)',
y = 'class',
color = 'Booster Version',
hover_data = ['Booster Version'])
return fig
if __name__ == '__main__':
app.run_server(debug = True, use_reloader = False)
Finally, the error that I get is the following:
dash._grouping.SchemaTypeValidationError: Schema: [<Output `success-pie-chart.figure`>, <Output `success-payload-scatter-chart.figure`>]
Path: ()
Expected type: (<class 'tuple'>, <class 'list'>)
Received value of type <class 'plotly.graph_objs._figure.Figure'>:
I really appreciate your time guys.
Please let me know if I can provide any more info or help clarify.
I've tested the functions that take the user's input and produce the pie and scatter charts outside Dash, and they worked fine. So, the error is arising from Dash.

Customize tcomb-form-native's data filds

I'm trying to customize the Data field of atcomb-form-native module.
I wish the date fields were a classic input field but I still tried different methods, I didn't succeed.
I tried to override the datepicker field style but put the style when opening the picker to insert the date and not around the message.
Instead of 'Tap here to select a date' I would like to insert a phrase at will. How can I do?
Also, how can I customize the date format? I tried following this issue of github but it didn't solve the problem.
This is the part of code for formatting the data:
config: {
format: date => {
let toBeFormatted = new Date(date);
return String('Valida dal' + toBeFormatted.format('DD/MM/YYYY'));
},
dateFormat: date => {
let toBeFormatted = new Date(date);
return String('Valida dal' + toBeFormatted.format('DD/MM/YYYY'));
},
timeFormat: date => {
let toBeFormatted = new Date(date);
return String('Valida dal' + toBeFormatted.format('DD/MM/YYYY'));
},
}
Okay. I can give you my code. I had a little trouble finding it, but finally, everything is in the tcomb documentation.
The two important points to answer your question are :
"defaultValueText" and "format: (date) => ..."
import React, { Component } from "react";
import Expo from "expo";
import t from "tcomb-form-native";
import moment from 'moment';
import { StyleSheet, Text, Date} from "react-native";
import { Button } from "react-native-elements";
const Form = t.form.Form;
Form.stylesheet.dateValue.normal.borderColor = '#d0d2d3';
Form.stylesheet.dateValue.normal.backgroundColor = '#ffffff';
Form.stylesheet.dateValue.normal.borderRadius= 5,
Form.stylesheet.dateValue.normal.color = 'grey';
Form.stylesheet.dateValue.normal.borderWidth = 1;
const User = t.struct({
pseudo: t.String,
birthday: t.Date,
});
const options = {
order: ['pseudo','birthday'],
fields: {
pseudo: {
placeholder: 'Enter Name',
error: 'Name is empty?',
},
birthday: {
mode: 'date',
label: 'birthday',
config: {
defaultValueText: 'Enter birthday', // Allows you to format the PlaceHolders !!
format: (date) => {
return moment(date).format('DD-MM-YYYY'); // Allows you to format the date !!
},
}
},
},
};
... ...
export default class SignUp extends Component {
state = {...
render() {
return (
<View style={styles.container}>
<Form
type={User}
ref={c => (this._form = c)} // assign a ref
options={options} //set form options
/>
<Button
title="Sign Up!"
buttonStyle={styles.button}
onPress={this.handleSubmit}
/>
</View>
);
}
}
} ...

Google chart breaks into two

I have given the data in the correct order. The render is somehow split between
2019 and 2018 and that too 2019 first and then 2018. Is there a fix for this? Or some property that causes this to happen?
The code is as follows:
import {GoogleCharts} from 'google-charts';
let graphRows = []
graphs[index].forEach(element => {
let dataArray = [];
dataArray.push(new Date(element["Date"].toString()));
dataArray.push(element['Net Asset Value']);
graphRows.push(dataArray);
});
//Load the charts library with a callback
GoogleCharts.load(drawChart);
function drawChart() {
// Standard google charts functionality is available as GoogleCharts.api after load
const data = new GoogleCharts.api.visualization.DataTable();
data.addColumn('date', 'Time');
data.addColumn('number', 'Net Asset Value');
data.addRows(graphRows);
// data.addRows(graphRowsReversed);
var options = {
hAxis: {
title: 'Date'
},
vAxis: {
title: 'Value'
},
explorer: { axis: 'horizontal' }
};
const line_chart = new GoogleCharts.api.visualization.LineChart(document.getElementById('chart-div'));
line_chart.draw(data, options);
}
graphs[index] is an array of objects each of which looks like this:
{
"Scheme Code": 145633,
"Scheme Name": "Mirae Asset Nifty 50 ETF (MAN50ETF)",
"ISIN Div Payout": {
"ISIN Growth": "INF769K01EG9"
},
"ISIN Div Reinvestment": "",
"Net Asset Value": 116.917,
"Repurchase Price": null,
"Sale Price": null,
"Date": "09-Apr-2019"
}

How to add comma in stacked column highchart in indian format?

I am using stacked column highchart. I am getting few value in column and tooltip. Now I want to show this value in Indian format with comma separator. Suppose I have a value like 123456789.So I want to show this value in 12,34,56,789 format. How can I do this? Please share with me if any body has any idea.
I tried this below code.
Highcharts.setOptions({
lang: {
thousandsSep: ','
}
});
But It gives 123,456,789 format, I want something like 12,34,56,789. The Indian format.
My codes are below:
function draw_charts(amount, interest , year)
{
/*Highcharts.setOptions({
lang: {
thousandsSep: ','
}
});*/
$('#chart_area').highcharts({
chart: {
type: 'column',
backgroundColor: 'transparent'
},
title: {
text: 'Year wise break-up'
},
xAxis: {
categories: year,
title: {
text: 'Year'
}
},
yAxis: {
min: 0,
title: {
text: 'Amount'
},
stackLabels: {
enabled: true,
style: {
fontWeight: 'bold',
color: (Highcharts.theme && Highcharts.theme.textColor) || 'gray'
}
}
},
legend: {
align: 'right',
x: -30,
verticalAlign: 'top',
y: -5,
floating: true,
backgroundColor: (Highcharts.theme && Highcharts.theme.background2) || 'white',
borderColor: '#CCC',
borderWidth: 1,
shadow: false
},
tooltip: {
headerFormat: '<b>{point.x}</b><br/>',
pointFormat: '{series.name}: {point.y}<br/>Total: {point.stackTotal}'
},
plotOptions: {
column: {
stacking: 'normal',
dataLabels: {
enabled: true,
color: (Highcharts.theme && Highcharts.theme.dataLabelsColor) || 'white',
style: {
textShadow: '0 0 3px black'
}
}
}
},
series: [{
name: 'Interest',
data: interest, color: '#7fb801'
},{
name: 'Principal',
data: amount, color: '#4fc1e9'
}],
exporting: { enabled: false },
credits: { enabled: false },
});
}
You can slightly modify the numberFormat function, changing from the lines (from source):
thousands = strinteger.length > 3 ? strinteger.length % 3 : 0;
// ...
ret += strinteger.substr(thousands).replace(/(\d{3})(?=\d)/g, '$1' + thousandsSep);
To these lines:
thousands = strinteger.length > 3 ? (strinteger.length - 1) % 2 : 0;
// ...
ret += strinteger.substr(thousands).replace(/(\d{2})(?=\d{3})/g, '$1' + thousandsSep);
Ending up with this function:
Highcharts.numberFormat = function (number, decimals, decimalPoint, thousandsSep) {
number = +number || 0;
decimals = +decimals;
var lang = Highcharts.getOptions().lang,
origDec = (number.toString().split('.')[1] || '').length,
decimalComponent,
strinteger,
thousands,
absNumber = Math.abs(number),
ret;
if (decimals === -1) {
decimals = Math.min(origDec, 20); // Preserve decimals. Not huge numbers (#3793).
} else if (!isNumber(decimals)) {
decimals = 2;
}
// A string containing the positive integer component of the number
strinteger = String(Highcharts.pInt(absNumber.toFixed(decimals)));
// Leftover after grouping into thousands. Can be 0, 1 or 3.
thousands = strinteger.length > 3 ? (strinteger.length - 1) % 2 : 0;
// Language
decimalPoint = Highcharts.pick(decimalPoint, lang.decimalPoint);
thousandsSep = Highcharts.pick(thousandsSep, lang.thousandsSep);
// Start building the return
ret = number < 0 ? '-' : '';
// Add the leftover after grouping into thousands. For example, in the number 42 000 000,
// this line adds 42.
ret += thousands ? strinteger.substr(0, thousands) + thousandsSep : '';
// Add the remaining thousands groups, joined by the thousands separator
ret += strinteger.substr(thousands).replace(/(\d{2})(?=\d{3})/g, '$1' + thousandsSep);
// Add the decimal point and the decimal component
if (decimals) {
// Get the decimal component, and add power to avoid rounding errors with float numbers (#4573)
decimalComponent = Math.abs(absNumber - strinteger + Math.pow(10, -Math.max(decimals, origDec) - 1));
ret += decimalPoint + decimalComponent.toFixed(decimals).slice(2);
}
return ret;
};
I've prefixed some function calls with Highcharts to make it work without a custom js-file.
See this JSFiddle demonstration of it in use.

Google charts multiline dynamic charts

Am new to PHP coding & have a few google charts working. All of these charts I've generated so far are based on (date,number of event occurrences) type of chart. I'm trying to plot a google chart whose data is the output of SQL query.
The output of SQL query looks as below
|SERIES|DATE_1|DATE_2|DATE_3|
|a|2|3|
|b|4|6|
|c|7|8|
Both SERIES & DATE_1 can vary. That is to say, based on various conditions in the SQL query, the number of DATE_ can be vary & so can the SERIES.
I would then have to pass this output to the google chart plot code.
Here is what i've tried coding so far
$link = mysql_connect("localhost", "user", "pass");
$dbcheck = mysql_select_db("database");
if ($dbcheck) {
$chart_array_1[] = "['MY_DATE','MY_NAME','#NUM_OCCURENCES']";
$result = mysql_query($sql);
if (mysql_num_rows($result) > 0) {
while ($row = mysql_fetch_assoc($result)) {
$my_date=$row["MY_DATE"];
$my_ins=$row["MY_NAME"];
$my_count=$row["MY_COUNT"];
$chart_array_1[]="['".$my_date."','".$my_ins."',".$my_count."]";
}
}
}
mysqli_close($link);
<script type="text/javascript">
// Load the Visualization API and the piechart package.
google.load('visualization', '1', {'packages':['corechart']});
// Set a callback to run when the Google Visualization API is loaded.
google.setOnLoadCallback(drawChart);
function drawChart() {
// Create our data table out of JSON data loaded from server.
var data_1 = google.visualization.arrayToDataTable([<?php echo (implode(",", $chart_array_1)); ?>])
var options = {
bar: {groupWidth: "6%"},
trendlines: {
1: {
type: 'linear',
color: 'green',
lineWidth: 3,
opacity: 0.3,
showR2: true,
visibleInLegend: true
}
},
chartArea: {
left: 70,
top: 61,
width:'95%',
height:'70%'
},
curveType: 'function',
//width: 1600,
height: 400,
pointSize: 4,
lineWidth: 2,
visibleInLegend: false,
vAxis: {
//title: "GC#",
logScale: true,
titleTextStyle: {
color: 'black'
}
},
hAxis: {
title: "TIMELINE",
titleTextStyle: {
bold: false,
color: 'black'
}
},
legend: {
position: 'top',
alignment: 'center',
textStyle: {
color: 'blue'
}
}
};
var chart_1 = new google.visualization.LineChart(document.getElementById('plot1'));
chart_1.draw(data_1, options);
}
</script>
I'm unable to plot the graph. I get the error "Data column(s) for axis #0 cannot be of type stringĂ—". Could someone please help me here.
I'd like to see a,b,c etc as separate series each while the date goes on to the X-Axis. Please note am after generating data dynamically using SQL query & not a static array which most examples demonstrate. Could someone please help?
Managed to implement thing a different way. Hence this question can be ignored.