Plot multiple y-axes in Plotly - matplotlib

I have the following code for my layout:
var layout = {
title:"Energy usage of green electrical appliances",
plot_bgcolor:"#000",
paper_bgcolor:"#000",
showlegend:false,
margin:"{l: 40, b: 40, r: 80, t: 40,}",
xaxis:{
title:"Date/Time",
autoscale:"true",
rangeselector: {
bgcolor:"#555",
},
yaxis:{
title:"Price",
autoscale:"true",
overlaying:"y2",
side:"left",
},
yaxis2: {
title:"Electricity Used",
autoscale:"true",
side:"right"
},
yaxis3:{
title:"AiJ/day",
autoscale:"true",
side:right
}
}
and the following code for my data:
var tracePrice= {name:"Price",type:"scatter",x:output[0]["datetime"],y:output[0]["price"],line:{color:"orange",width:2},};
var traceElecUsed= {name:"Elec",type:"bar",x:output[0]["datetime"],y:output[0]["Elec"],line:{color:"cyan",width:2},};
var traceAiJ= {name:"aij",type:"scatter",x:output[0]["datetime"],y:output[1]["aijpercent"],yaxis:"y2",marker:{color:"#fff"},line:{color:"#555",width:1}};
return resolve([tracePrice,traceElecUsed,traceAiJ]);
The thing is, everything works fine until I plot traceElecUsed. The units it usesare in the thousands, whereas price is often under £5 and AiJ is a percentage of 0-100%. I don't know if this is the root of the issue. If I remove it everything works fine.

The stackoverflow curse has got me again; I struggle for hours with something then once I've posted it the answer appears.
For those of you in the future that need this info, it relies on 'overlaying'
yaxis3: {
title:"Aij",
autoscale:"true",
overlaying:"y2",
side:"right"
}

Related

html2pdf fit image to pdf

I finally got my html2pdf to work showing my web page just how I want it in the pdf(Any other size was not showing right so I kept adjusting the format size until it all fit properly), and the end result is exactly what I want it to look like... EXCEPT even though my aspect ratio is correct for a landscape, it is still using a very large image and the pdf is not standard letter size (Or a4 for that matter), it is the size I set. This makes for a larger pdf than necessary and does not print well unless we adjust it for the printer. I basically want this exact image just converted to a a4 or letter size to make a smaller pdf. If I don't use the size I set though things are cut off.
Anyway to take this pdf that is generated and resize to be an a4 size(Still fitting the image on it). Everything I try is not working, and I feel like I am missing something simple.
const el = document.getElementById("test);
var opt = {
margin: [10, 10, 10, 10],
filename: label,
image: { type: "jpeg", quality: 0.98 },
//pagebreak: { mode: ["avoid-all", "css"], after: ".newPage" },
pagebreak: {
mode: ["css"],
avoid: ["tr"],
// mode: ["legacy"],
after: ".newPage",
before: ".newPrior"
},
/*pagebreak: {
before: ".newPage",
avoid: ["h2", "tr", "h3", "h4", ".field"]
},*/
html2canvas: {
scale: 2,
logging: true,
dpi: 192,
letterRendering: true
},
jsPDF: {
unit: "mm",
format: [463, 600],
orientation: "landscape"
}
};
var doc = html2pdf()
.from(el)
.set(opt)
.toContainer()
.toCanvas()
.toImg()
.toPdf()
.save()
I have been struggling with this a lot as well. In the end I was able to resolve the issue for me. What did the trick for me was setting the width-property in html2canvas. My application has a fixed width, and setting the width of html2canvas to the width of my application, scaled the PDF to fit on an A4 paper.
html2canvas: { width: element_width},
Try adding the above option to see if it works. Try to find out the width of your print area in pixels and replace element_width with that width.
For completeness: I am using Plotly Dash to create web user interfaces. On my interface I include a button that when clicked generates a PDF report of my dashboard. Below I added the code that I used for this, in case anybody is looking for a Dash solution. To get this working in Dash, download html2pdf.bundlemin.js and copy it to the assets/ folder. The PDF file will be downloaded to the browsers default downloads folder (it might give a download prompt, however that wasn't how it worked for me).
from dash import html, clientside_callback
import dash_bootstrap_components as dbc
# Define your Dash app in the regular way
# In the layout define a component that will trigger the download of the
# PDF report. In this example a button will be responsible.
app.layout = html.Div(
id='main_container',
children = [
dbc.Button(
id='button_download_report',
children='Download PDF report',
className='me-1')
])
# Clientside callbacks allow you to directly insert Javascript code in your
# dashboards. There are also other ways, like including your own js files
# in the assets/ directory.
clientside_callback(
'''
function (button_clicked) {
if (button_clicked > 0) {
// Get the element that you want to print. In this example the
// whole dashboard is printed
var element = document.getElementById("main_container")
// create a date-time string to use for the filename
const d = new Date();
var month = (d.getMonth() + 1).toString()
if (month.length == 1) {
month = "0" + month
}
let text = d.getFullYear().toString() + month + d.getDay() + '-' + d.getHours() + d.getMinutes();
// Set the options to be used when printing the PDF
var main_container_width = element.style.width;
var opt = {
margin: 10,
filename: text + '_my-dashboard.pdf',
image: { type: 'jpeg', quality: 0.98 },
html2canvas: { scale: 3, width: main_container_width, dpi: 300 },
jsPDF: { unit: 'mm', format: 'A4', orientation: 'p' },
// Set pagebreaks if you like. It didn't work out well for me.
// pagebreak: { mode: ['avoid-all'] }
};
// Execute the save command.
html2pdf().from(element).set(opt).save();
}
}
''',
Output(component_id='button_download_report', component_property='n_clicks'),
Input(component_id='button_download_report', component_property='n_clicks')
)

WebRTC AGC (Automatic Gain Control): can it really be disabled?

:)
I've installed AppRTC (https://github.com/webrtc/apprtc) to a separate server to try out more flexible control of the WebRTC parameters.
The main task is to disable Automatic Gain Control (AGC).
The following steps have been performed:
The parameters for the audio-stream:
{
video:
{
frameRate: 30,
width: 640,
height: 480
},
audio:
{
echoCancellation: true,
noiseSuppression: true,
autoGainControl: false
}
}
The GainNode filter has been added via audioContext.createGain() and has received a fixed value via gainNode.gain.value
To be able to test the AGC absence - a graphical audio meter has been added using audioContext.createScriptProcessor(...).onaudioprocess
The problem is that in fact the AGC is not disabled and Gain still remains dynamic.
During a long monotone loud sound the analyzer drops to a significantly lower value after 5-6 seconds.
And after 5-6 seconds of silence gets back to previous range.
All this has been tested on macOs Catalina 10.15.7, in the following browsers:
Mozilla Firefox 82.0.3,
Google Chrome 86.0.4240.198,
Safari 14.0 (15610.1.28.1.9, 15610),
and also on iOS 14.2 Safari.
The question: is there a functioning possibility to turn off AGC and to follow that not only "by hearing" but also by the meter values?
The full code of the gain fixation method:
src/web_app/html/index_template.html
var loadingParams = {
errorMessages: [],
isLoopback: false,
warningMessages: [],
roomId: '101',
roomLink: 'https://www.xxxx.com/r/101',
// mediaConstraints: {"audio": true, "video": true},
mediaConstraints: {video: {frameRate: 30, width: 640, height: 480}, audio: {echoCancellation: true, noiseSuppression: true, autoGainControl: false}},
offerOptions: {},
peerConnectionConfig: {"bundlePolicy": "max-bundle", "iceServers": [{"urls": ["turn:www.xxxx.com:3478?transport=udp", "turn:www.xxxx.com:3478?transport=tcp"], "username": "demo", "credential": "demo"}, {"urls": ["stun:www.xxxx.com:3478"], "username": "demo", "credential": "demo"}], "rtcpMuxPolicy": "require"},
peerConnectionConstraints: {"optional": []},
iceServerRequestUrl: 'https://www.xxxx.com//v1alpha/iceconfig?key=',
iceServerTransports: '',
wssUrl: 'wss://www.xxxx.com:8089/ws',
wssPostUrl: 'https://www.xxxx.com:8089',
bypassJoinConfirmation: false,
versionInfo: {"time": "Wed Sep 23 12:49:00 2020 +0200", "gitHash": "78600dbe205774c115cf481a091387d928c99d6a", "branch": "master"},
};
src/web_app/js/appcontroller.js
AppController.prototype.gainStream = function (stream, gainValue) {
var max_level_L = 0;
var old_level_L = 0;
var cnvs = document.createElement('canvas');
cnvs.style.cssText = 'position:fixed;width:320px;height:30px;z-index:100;background:#000';
document.body.appendChild(cnvs);
var cnvs_cntxt = cnvs.getContext("2d");
var videoTracks = stream.getVideoTracks();
var context = new AudioContext();
var mediaStreamSource = context.createMediaStreamSource(stream);
var mediaStreamDestination = context.createMediaStreamDestination();
var gainNode = context.createGain();
var javascriptNode = context.createScriptProcessor(1024, 1, 1);
mediaStreamSource.connect(gainNode);
mediaStreamSource.connect(javascriptNode);
gainNode.connect(mediaStreamDestination);
javascriptNode.connect(mediaStreamDestination);
javascriptNode.onaudioprocess = function(event){
var inpt_L = event.inputBuffer.getChannelData(0);
var instant_L = 0.0;
var sum_L = 0.0;
for(var i = 0; i < inpt_L.length; ++i) {
sum_L += inpt_L[i] * inpt_L[i];
}
instant_L = Math.sqrt(sum_L / inpt_L.length);
max_level_L = Math.max(max_level_L, instant_L);
instant_L = Math.max( instant_L, old_level_L -0.008 );
old_level_L = instant_L;
cnvs_cntxt.clearRect(0, 0, cnvs.width, cnvs.height);
cnvs_cntxt.fillStyle = '#00ff00';
cnvs_cntxt.fillRect(10,10,(cnvs.width-20)*(instant_L/max_level_L),(cnvs.height-20)); // x,y,w,h
}
gainNode.gain.value = gainValue;
var controlledStream = mediaStreamDestination.stream;
for (const videoTrack of videoTracks) {
controlledStream.addTrack(videoTrack);
}
return controlledStream;
};
AppController.prototype.onLocalStreamAdded_ = function(stream) {
trace('User has granted access to local media.');
this.localStream_ = this.gainStream(stream, 100);
this.infoBox_.getLocalTrackIds(this.localStream_);
if (!this.roomSelection_) {
this.attachLocalStream_();
}
};
Thank you!
Best Regards,
Andrei Costenco
I think the problem you ran into is that echoCancellation and noiseSuppression do modify the signal as well. Since you mentioned that you are using a long monotone sound to test your code it could very well be that the noiseSuppression algorithm tries to reduce that "noise".
Unfortunately there is no way to tell why the signal was modified. You have to trust the browser here that it actually has switched off the gain control and that all remaining modifications come from the other two algorithms.
If you don't want to fully trust the browser you could also experiment a bit by using other sounds to run your tests. It should not be "noisy" but it's difficult to say what get's detected by the browser as noise and what doesn't.

Getting all bids from each Header bidding partners

We are implementing some header bidding partners on our wrapper using prebid. Is it possible to get all bids from each ssp.
Any help appreciated.
If you’re asking about demand, this is dependent on each SSP. For example there may be a segment pixel or placement in one SSP that will always give you a $10 bid, but that wouldnt apply to the other SSPs.
If your asking about getting data on all the bids, you may want to check out pbjs.getBidResponses() which returns an object with the ad units and bids
Heres a sample response from pbjs.getBidResponses() which can then be used however you'd need that data:
{
"div-id-one": {
"bids": [
{
"bidderCode": "appnexus",
"width": 970,
"height": 250,
"statusMessage": "Bid available",
"adId": "1293a95bb3e9615",
"mediaType": "banner",
"creative_id": 77765220,
"cpm": 0.7826,
"adUrl": "https://...",
"requestId": "57f961f3-a32b-45df-a180-9d5e53fb9070",
"responseTimestamp": 1513707536256,
"requestTimestamp": 1513707535321,
"bidder": "appnexus",
"adUnitCode": "div-id-one",
"timeToRespond": 935,
"pbLg": "0.50",
"pbMg": "0.70",
"pbHg": "0.78",
"pbAg": "0.75",
"pbDg": "0.78",
"pbCg": "0.78",
"size": "970x250",
"adserverTargeting": {
"hb_bidder": "appnexus",
"hb_adid": "1293a95bb3e9615",
"hb_pb": "0.78",
"hb_size": "970x250"
}
}
]
},
"div-id-two": {
"bids": []
}
}
Theres also a great example on prebid.org on how to output this to console.table that could be helpful as well:
var responses = pbjs.getBidResponses();
var output = [];
for (var adunit in responses) {
if (responses.hasOwnProperty(adunit)) {
var bids = responses[adunit].bids;
for (var i = 0; i < bids.length; i++) {
var b = bids[i];
output.push({
'adunit': adunit, 'adId': b.adId, 'bidder': b.bidder,
'time': b.timeToRespond, 'cpm': b.cpm, 'msg': b.statusMessage
});
}
}
}
if (output.length) {
if (console.table) {
console.table(output);
} else {
for (var j = 0; j < output.length; j++) {
console.log(output[j]);
}
}
} else {
console.warn('NO prebid responses');
}
There is also a chrome extensions called Prebid helper that do the same as console snippet but with less clicks.
However that is useful for initial setup debug. If you need to gather aggregated data on all demand partners - bids, timeouts, wins etc. You will need to run third party wrapper analytics or use analytics adapter. It's not free but it usually is priced depending on your load on the analytics server. For example https://headbidder.net/pricing
Try out the Chrome Extension called Adwizard. It's been built to debug prebid setups. Shows you all networks and bids per adunit. CPM and Size included.
https://chrome.google.com/webstore/detail/adwizard/kndnhcfdajkaickocacghchhpieogbjh/?ref=stackoverflow

Can Gulp change LESS variables?

I'm looking to toggle IE8 mode in my LESS files and automated the file generation in Gulp.
This is where I stopped in what to pass gulp-less (minus a bunch of stuff):
var IE = true;
var LESSConfig = {
plugins: [ ... ],
paths: LESSpath,
ie8compat: IE, //may as well toggle this
// Set in variables.less, #ie:false; - used in mixin & CSS guards
// many variations tried
// globalVars: [ { "ie":IE } ],
modifyVars:{ "ie":IE }
};
...
.pipe( less ( LESSConfig ) )
Is variable modification not supported in Gulp?
I'd like to avoid using gulp-modify et al if I can. I'd like to keep the build system fairly abstracted from the source files.
modifyVars is working for me now:
...
var LESSConfig = {
paths: paths.LESSImportPaths,
plugins: [
LESSGroupMediaQueries,
LESSautoprefix
],
modifyVars: {
ie: 'false'
}
};
var LESSConfigIE = {
paths: paths.LESSImportPaths,
modifyVars: {
ie: 'true'
}
};
function processLESS (src, IE, dest){
return gulp.src(src)
.pipe( $.if( IE, $.less( LESSConfigIE ), $.less( LESSConfig ) ) )
.pipe( $.if( IE, $.rename(function(path) { path.basename += "-ie"; }) ) )
.pipe( gulp.dest(dest) )
}
// build base.css files
gulp.task('base', function() {
return processLESS( paths.Base + '/*.less', false, paths.dest );
});
// build base-ie.css files for IE
gulp.task('baseIE', function() {
return processLESS( paths.Base + '/*.less', true, paths.dest );
});
Since I could not get this to work with gulp-lessand it became apparent to me that the application of globalVars and modifyVars are both broken, I came up with a different solution.
You can use gulp-append-prepend to write your variables into the file before gulp-less processes it. A little less elegant but, on the plus side, it actually works.
Something like this:
gulp.src('main.less')
.pipe(gap.prependText('#some-global-var: "foo";'))
.pipe(gap.appendText('#some-modify-var: "bar";'))
.pipe(less())
.pipe(gulp.dest('./dest/'));
Nowadays (2019) this problem seems to be fixed.
However it cost me still a lot of time to get it running.
Here is what I did:
gulp.task('lessVariants', ['less'], function() {
return gulp.src('less/styles.less', {base:'less/'})
.pipe(less({modifyVars:{'#color1': '#535859'}))
.pipe(less({modifyVars:{'#color2': '#ff0000'}))
.pipe(less({modifyVars:{'#color3': '#ccffcc'}))
.pipe(rename('styles.modified.css'))
.pipe(cleanCSS())
.pipe(gulp.dest(distFolder + 'css'))
})
This did not work. Only the last variable was modified. I changed it as follows to get it working:
gulp.task('lessVariants', ['less'], function() {
return gulp.src('less/styles.less', {base:'less/'})
.pipe(less({modifyVars: {
'#color1': '#535859',
'#color2': '#ff0000',
'#color3': '#ccffcc',
}}))
.pipe(rename('styles.variant.css'))
.pipe(cleanCSS())
.pipe(gulp.dest(distFolder + 'css'))
})

Adding extra information above the node in cytoscape.js

Using cytoscape.js to draw a graph. I need to add circle above the node at top-right position. After drawing the graph, is there any API wherein we can get positions of nodes.
Also, I have used the code as follows:
elements : {
nodes : [ {
data : {
id : '1',
name : 'A'
}
}
]
}
var pos = cy.nodes("#1").position();
'#1' is the ID of the node in the data attribute. However, we are not able to add the node/circle at that exact position.
If you want to get something like:
then this code adds the circle to a node knowing it's id:
function addCircle(nodeId, circleText){
var parentNode = cy.$('#' + nodeId);
if (parentNode.data('isCircle') || parentNode.data('circleId'))
return;
parentNode.lock();
var px = parentNode.position('x') + 10;
var py = parentNode.position('y') - 10;
var circleId = (cy.nodes().size() + 1).toString();
parentNode.data('circleId', circleId);
cy.add({
group: 'nodes',
data: { weight: 75, id: circleId, name: circleText, isCircle: true },
position: { x: px, y: py },
locked: true
}).css({
'background-color': 'yellow',
'shape': 'ellipse',
'background-opacity': 0.5
}).unselectify();
}
// ...
addCircle('1', 'Bubble A');
but it must be called after the node's positions are known, when the layout settles down.
The locking is there to prevent that node and it's circle get apart.
jsFiddle demo: http://jsfiddle.net/xmojmr/wvznb9pf/
Using compound node which would keep the node and it's circle together would be probably better, once the support for positioning child nodes is implemented.
Disclaimer: I'm cytoscape.js newbie, use at your own risk