How to prevent stacked bars aggregating by date in DASH? - plotly-dash

I have a simple dataframe who's index is a time series. The dataframe looks something like this:
I want to shows stacked bars for the 'Percent_male' and 'Percent_Female' columns using plotly.graph_objects and Dash. This works fine for data rows who's date index are unique. However, any rows whose index is not a unique date, such as for '2022-10-10' for example, in which there are 4 data samples occurring on the same date, the 4 samples all aggregate into one large stacked bar, but I wish to keep separate bars per sample/ row. The end result looks like:
The 2 traces are quite simply:
`trace1 = go.Bar(
x = df.index,
y = df.Percent_Male,
name = '% Male',
)
trace2 = go.Bar(
x = df.index,
y = df.Percent_Female,
name = '% Female'
)`
And the Plotly go figure is created in the Dash app.layout like so:
`app.layout = html.Div([
html.H1('Gender Balance'),
html.Div([
dcc.Graph(
id='plot1',
figure={
'data': data2,
'layout':go.Layout(
title='Historic',
height=640,
width=980,
barmode='stack',
)
}
)],style={'display':'inline-block'}
])`
Is there any way to plot unique bars per dataframe column?

Related

Extracting a list of dicts for a Pandas column

I have a list of dictionaries within a pandas column to designate landing pages for a particular keyword.
keyword | 07-31-2019 | landing_pages |
cloud api | 50 | [{'url' : 'www.example.com', 'date' : '07-31-2019'}, {'url' ... ]|
database | 14 | [{'url' : 'www.example.com/2', 'date' : '08-30-2019'} ... ]|
*There are actually many date columns, but I've only shown 1 for example.
My issue is that I already have columns for each date, so I want to extract the landing pages as a list and have that as a new column.
keyword | 07-31-2019 | landing_pages
cloud api | 50 | www.example.com, www.example.com/other
database | 14 | www.example.com/2, www.example.com/3
So far, I've tried using json_normalize, which gave me a new table of dates and landing pages. I've tried getting the values with list comprehension, but that gave me the wrong result as well. One way I can think of is to use loops to solve the problem, but I'm concerned that's not efficient. How can I do this efficiently?
Use generator with join for extract url values (if data are dictionaries):
df['landing_pages'] = df['landing_pages'].apply(lambda x: ', '.join(y['url'] for y in x))
print (df)
keyword 07-31-2019 landing_pages
0 cloud api 50 www.example.com
1 database 14 www.example.com/2
If not working because strings repr of dictionaries:
import ast
df['landing_pages'] = df['landing_pages']
.apply(lambda x: ', '.join(y['url'] for y in ast.literal_eval(x)))
EDIT: If want maximal url by recent dates create DataFrame with adding new keys by index values, then convert datetimes from strings and last use DataFrameGroupBy.idxmax for index of maximum datetimes, select by DataFrame.loc for rows with urls and last assign column url to original DataFrame:
L = [dict(x, **{'i':k}) for k, v in df['landing_pages'].items() for x in v]
df1 = pd.DataFrame(L)
df1['date'] = pd.to_datetime(df1['date'])
df['url by max date'] = df1.loc[df1.groupby('i')['date'].idxmax()].set_index('i')['url']

Sorting Data from Query

How can i sort my data by the last digit. I'm trying to sort a list of locations that look like AQ045A, the last digit being the height level.
So the data is a series of locations
AG045A,
AN045B,
AG046B,
AG046C,
SELECT STOLOC
FROM locmst_view
WHERE wh_id = 'US_3278'
AND locsts = 'E'
AND useflg = 1
AND sto_zone_cod LIKE '%FCC%'
ORDER BY right(STOLOC, 1),
STOLOC

Series Grouping SSRS

I have the following data in the dataset
Key Assignee Sev InOps InTek
1 A 1 Y Y
2 B 2 Y N
3 C 3 N Y
Need to plot the chart as follows so that I get
Sev on X Axis
Count(Key) on Y
Assignee belongs to Ops (Y) as Ops bar
Assignee belongs to Tek(Y) as Tek bar -For each severity we will have two bars then , one for Ops and another for Tek
which will show as follows
Sev 1 Ops Tek
1 1
Sev2 1 0
Sev3 0 1
I have the chart configuration done as follows
In Count I have dragged the Key column
In Category group I have the Sev column
in the series group , do I need to put two series opscolumn and tek respectively ?
The simplest way to do this, if possible, would be to pivot the data when generating the Dataset, i.e. having something like this:
From here it's trivial to create the Chart - Series based on InType, Category based on Severity and the data is a Count of Key.
If you can't pivot your data, create a Chart like this:
The expression for the first Chart Series is:
=Sum(IIf(Fields!InOps.Value = "Y", 1, 0))
and the second:
=Sum(IIf(Fields!InTek.Value = "Y", 1, 0))
It's also useful to set a custom Legend text for each of the Series:
Either way, you get the required result:

MySQL query to assign values to a field based in an iterative manner

I am using a MySql table with 500,000 records. The table contains a field (abbrevName) which stores a two-character representation of the first two letters on another field, name.
For example AA AB AC and so on.
What I want to achieve is the set the value of another field (pgNo) which stores a value for page number, based on the value of that records abbrevName.
So a record with an abbrevName of 'AA' might get a page number of 1, 'AB' might get a page number of 2, and so on.
The catch is that although multiple records may have the same page number (after all multiple entities might have a name beginning with 'AA'), once the amount of records with the same page number reaches 250, the page number must increment by one. So after 250 'AA' records with a page number of 1, we must assign futher 'AA records with a page number of 2, and so on.
My Pseudocode looks something like this:
-Count distinct abbrevNames
-Count distinct abbrevNames with more than 250 records
-For the above abbrevNames count the the sum of each divided by 250
-Output a temporary table sorted by abbrevName
-Use the total number of distinct page numbers with 250 or less records to assign page numbers incrementally
I am really struggling to put anything together in a query that comes close to this, can anyone help with my logic or some code ?
Please have a try with this one:
SELECT abbrevNames, CAST(pagenumber AS signed) as pagenumber FROM (
SELECT
abbrevNames
, IF(#prev = abbrevNames, #rows_per_abbrev:=#rows_per_abbrev + 1, #pagenr:=#pagenr + 1)
, #prev:=abbrevNames
, IF(#rows_per_abbrev % 250 = 0, #pagenr:=#pagenr + 1, #pagenr) AS pagenumber
, IF(#rows_per_abbrev % 250 = 0, #rows_per_abbrev := 1, #rows_per_abbrev)
FROM
yourTable
, (SELECT #pagenr:=0, #prev:=NULL, #rows_per_abbrev:=0) variables_initialization
ORDER BY abbrevNames
) subquery_alias
UPDATE: I had misunderstood the question a bit. Now it should work

MySQL - Perl- Order by - How to display ABS(PartNum) DESC but, three different (PartNum) categories?

Sorry for my inaccurate syntax. New to this.
I need to select part numbers in three different groups.
A different qty for each group.
Each group individually sorted ABS desc.
my $fromrow = CGI::param('from');## vague but put here to show a sort of pagination ##
my $nextrow = CGI::param('next');
my $grabpartnumbers = $hookup->prepare(qq{
SELECT `New`,`Used`,`NOS`,`PartNum`,`Description`,`Price`
FROM `Partstable`
WHERE `instock` = ? AND `QTY` > ? AND `New` = ?
ORDER BY ABS(PartNum) LIMIT ?,?});
$grabpartnumbers->execute('1','10','1',$fromrow,$nextrow);
while(#row = $grabpartnumbers->fetchrow_array()) {
#do stuff
Works fine, for one "column" eg "New".
However, I want to display like:
New Stock
4 results
NOS
6 results
Used Stock
10 results
Additional problems will arise for me when one of the three "columns" have no more data to display. At that point, I just want to display the remaining result or nothing (not even the title header) if results = 0 for that cat.
Is this possible or do I need to prepare three different queries and possibly push each into their own arrays to decipher what to display in some loops?
This is VERY advanced for me so, please be verbose with examples. (dumb it down to my level of comprehension (-; )
Thanks..
EDIT:
My Partstable rows look like
ID|PartNum|New|Used|NOS|Qty|instock|Description|Price
1|132452 |1 |0 |0 | 24|y |12ax7 yada |3.00
I want to display three "areas" on the same page by order of "importance". "New" take priority.
New Stock 4 results
NOS 6 results
Used Stock 10 results
What you need to achieve is a little bit difficult to precisely comprehend, but it looks like you could potentially be just fine with a full-SQL solution (clever use of GROUP BY, etc.).
Regarding the current solution with Perl, and assuming I understand your example correctly, something like this would work as a starting point for you to play around and adapt to your actual dataset.
Warning: Code tested against syntax only!
my $fromrow = CGI::param('from');## vague but put here to show a sort of pagination ##
my $nextrow = CGI::param('next');
# Columns of interest, sorted by descending order of importance
my #interesting_columns = qw(
New
Used
NOS
PartNum
Description
Price
);
my $interesting_columns_expr = join(', ', map { $_ = "`$_`" } #interesting_columns);
my $grabpartnumbers = $hookup->prepare(qq{
SELECT $interesting_columns_expr
FROM `Partstable`
WHERE `instock` = ? AND `QTY` > ?
ORDER BY ABS(PartNum) LIMIT ?,?
});
$grabpartnumbers->execute('1','10',$fromrow,$nextrow);
# Compute results
my %result_counter;
while ( my $row = $grabpartnumbers->fetchrow_hashref() ) {
foreach my $column_name ( keys %$row ) {
$result_counter{$column_name} += $row->{$column_name};
}
}
# Display results
for my $column_name ( #interesting_columns ) {
if (exists $result_counter{$column_name}) {
print join( ':', $column_name, $result_counter{$column_name} );
}
}