Class ConstrDefaults
All default values of the construct actions are static members of this class. So they can be stored from one construction to the other.
Inherited Members
Namespace: CADability.Actions
Assembly: CADability.dll
Syntax
public class ConstrDefaults : ConstructAction, ICommandHandler, IPropertyEntry
Constructors
| Improve this Doc View SourceConstrDefaults()
Empty constructor
Declaration
public ConstrDefaults()
Fields
| Improve this Doc View SourceDefaultArcCenter
The default center of a circle or arc. Normally it is set at the end of an arc-constrution to the center of that arc/circle, so a new arc/circle can start with the center of the last arc/circle by using the TAB-button within the center-textfield to accept the default center.
Declaration
public static ConstructAction.DefaultGeoPoint DefaultArcCenter
Field Value
| Type | Description |
|---|---|
| ConstructAction.DefaultGeoPoint |
DefaultArcDiameter
The default diameter of a circle or arc. Normally it is set at the end of an arc-constrution to the diameter of that arc/circle, so a new arc/circle can start with the radius of the last arc/circle by using the TAB-button within the diameter-textfield to accept the default diameter.
Declaration
public static ConstructAction.DefaultLength DefaultArcDiameter
Field Value
| Type | Description |
|---|---|
| ConstructAction.DefaultLength |
DefaultArcDirection
The default direction of an arc. Normally it is set at the end of an arc-constrution to the direction of that arc, so a new arc can start with the direction of the last arc by using the TAB-button within the direction-textfield to accept the default direction.
Declaration
public static ConstructAction.DefaultBoolean DefaultArcDirection
Field Value
| Type | Description |
|---|---|
| ConstructAction.DefaultBoolean |
DefaultArcRadius
The default radius of a circle or arc. Normally it is set at the end of an arc-constrution to the radius of that arc/circle, so a new arc/circle can start with the radius of the last arc/circle by using the TAB-button within the radius-textfield to accept the default radius.
Declaration
public static ConstructAction.DefaultLength DefaultArcRadius
Field Value
| Type | Description |
|---|---|
| ConstructAction.DefaultLength |
DefaultBoxHeight
The default height of a 3D-box. Normally it is set at the end of a box-constrution to the height of that box, so a new box can start with the height of the last box by using the TAB-button within the height-textfield to accept the default height.
Declaration
public static ConstructAction.DefaultLength DefaultBoxHeight
Field Value
| Type | Description |
|---|---|
| ConstructAction.DefaultLength |
DefaultCopyObjects
The default way of the modification of activated objects. If DefaultCopyObjects is true, a copy of the activated objects is modified, if it is false, the original objects are modified.
Declaration
public static ConstructAction.DefaultBoolean DefaultCopyObjects
Field Value
| Type | Description |
|---|---|
| ConstructAction.DefaultBoolean |
DefaultCutOffAngle
The default angle of the cut-off actions in the tools-menue. Normally it is set at the end of a cut-off action to current angle, so a cut off action can start with the angle of the last action by using the TAB-button within the cut off angle-textfield to accept the default angle.
Declaration
public static ConstructAction.DefaultAngle DefaultCutOffAngle
Field Value
| Type | Description |
|---|---|
| ConstructAction.DefaultAngle |
DefaultCutOffLength
The default length of the cut-off actions in the tools-menue. Normally it is set at the end of a cut off-action to current length, so a cut off action can start with the length of the last action by using the TAB-button within the cut off length-textfield to accept the default length.
Declaration
public static ConstructAction.DefaultLength DefaultCutOffLength
Field Value
| Type | Description |
|---|---|
| ConstructAction.DefaultLength |
DefaultCutOffMethod
The default method of the cut-off actions in the tools-menue. Normally it is set at the end of a cut-off action to current method, so a cut off action can start with the method of the last action by using the TAB-button within the cut off angle-textfield to accept the default method.
Declaration
public static ConstructAction.DefaultInteger DefaultCutOffMethod
Field Value
| Type | Description |
|---|---|
| ConstructAction.DefaultInteger |
DefaultDimensionMethod
The default way of collecting and handling points for a dimension ("0" means only 2 Points, "1" means multiple point input, "2" means 2-point-dimension referred to the first point).
Declaration
public static ConstructAction.DefaultInteger DefaultDimensionMethod
Field Value
| Type | Description |
|---|---|
| ConstructAction.DefaultInteger |
DefaultDimensionPointMethod
The default way of collecting a point for a point or labeling dimension ("true" means snap points, "false" means perpendicular foot points of objects).
Declaration
public static ConstructAction.DefaultBoolean DefaultDimensionPointMethod
Field Value
| Type | Description |
|---|---|
| ConstructAction.DefaultBoolean |
DefaultDimPoint
The locationpoint of a dimension. Normally it is set at the end of a dimension-constrution to the current position of that dimension, so a new dimension can start at the location point of the last dimension (plus an offset) by using the TAB-button within the dimensionpoint-textfield to accept the default point.
Declaration
public static ConstructAction.DefaultGeoPoint DefaultDimPoint
Field Value
| Type | Description |
|---|---|
| ConstructAction.DefaultGeoPoint |
DefaultDirectionOffset
The default method for the way to detect the direction-offset from an object. 0=original, 1=right, 2=opposite, 3=left
Declaration
public static ConstructAction.DefaultInteger DefaultDirectionOffset
Field Value
| Type | Description |
|---|---|
| ConstructAction.DefaultInteger |
DefaultDirectionPoint
The default method for the way to detect the direction from an object. 0=startpoint, 1=start/endpoint, 2=endpoint, 3=midpoint, 4=direction of mouseposition
Declaration
public static ConstructAction.DefaultInteger DefaultDirectionPoint
Field Value
| Type | Description |
|---|---|
| ConstructAction.DefaultInteger |
DefaultEllipseCenter
The default center of an ellipse or ellipsenarc. Normally it is set at the end of an ellipse-constrution to the center of that ellipse, so a new ellipse can start with the center of the last ellipse by using the TAB-button within the center-textfield to accept the default center.
Declaration
public static ConstructAction.DefaultGeoPoint DefaultEllipseCenter
Field Value
| Type | Description |
|---|---|
| ConstructAction.DefaultGeoPoint |
DefaultEllipseMajorRadius
The default majorradius of an ellipse or ellipsearc. Normally it is set at the end of an ellipse-constrution to the majorradius of that ellipse(arc), so a new ellipse(arc) can start with the majorradius of the last ellipse(arc) by using the TAB-button within the majorradius-textfield to accept the default majorradius.
Declaration
public static ConstructAction.DefaultLength DefaultEllipseMajorRadius
Field Value
| Type | Description |
|---|---|
| ConstructAction.DefaultLength |
DefaultEllipseMinorRadius
The default minorradius of an ellipse or ellipsearc. Normally it is set at the end of an ellipse-constrution to the minorradius of that ellipse(arc), so a new ellipse(arc) can start with the minorradius of the last ellipse(arc) by using the TAB-button within the minorradius-textfield to accept the default minorradius.
Declaration
public static ConstructAction.DefaultLength DefaultEllipseMinorRadius
Field Value
| Type | Description |
|---|---|
| ConstructAction.DefaultLength |
DefaultExpandDist
Declaration
public static ConstructAction.DefaultLength DefaultExpandDist
Field Value
| Type | Description |
|---|---|
| ConstructAction.DefaultLength |
DefaultExtrudeDirection
The default direction of an extrude-action.
Declaration
public static ConstructAction.DefaultGeoVector DefaultExtrudeDirection
Field Value
| Type | Description |
|---|---|
| ConstructAction.DefaultGeoVector |
DefaultLineAngle
The default angle of a line. Normally it is set at the end of a line-constrution to the angle of that line, so a new line can start with the angle of the last line by using the TAB-button within the angle-textfield to accept the default angle.
Declaration
public static ConstructAction.DefaultAngle DefaultLineAngle
Field Value
| Type | Description |
|---|---|
| ConstructAction.DefaultAngle |
DefaultLineDirection
The default direction of a line. Normally it is set at the end of a line-constrution to the direction of that line, so a new line can start with the direction of the last line by using the TAB-button within the direction-textfield to accept the default direction.
Declaration
public static ConstructAction.DefaultGeoVector DefaultLineDirection
Field Value
| Type | Description |
|---|---|
| ConstructAction.DefaultGeoVector |
DefaultLineDist
The default dist of a parallel-line. Normally it is set at the end of a line-constrution to the distance of that line to its parallel source, so a new line can start with the distance of the last line by using the TAB-button within the length-textfield to accept the default angle.
Declaration
public static ConstructAction.DefaultLength DefaultLineDist
Field Value
| Type | Description |
|---|---|
| ConstructAction.DefaultLength |
DefaultLineLength
The default length of a line. Normally it is set at the end of a line-constrution to the length of that line, so a new line can start with the length of the last line by using the TAB-button within the length-textfield to accept the default length.
Declaration
public static ConstructAction.DefaultLength DefaultLineLength
Field Value
| Type | Description |
|---|---|
| ConstructAction.DefaultLength |
DefaultLinePosition
The default position a tangent line with direction (Middle or End).
Declaration
public static ConstructAction.DefaultBoolean DefaultLinePosition
Field Value
| Type | Description |
|---|---|
| ConstructAction.DefaultBoolean |
DefaultRectHeight
The default height of a rectangle/parallelogram. Normally it is set at the end of a rectangle-constrution to the height of that rectangle, so a new rectangle/parallelogram can start with the height of the last rectangle/parallelogram by using the TAB-button within the height-textfield to accept the default height.
Declaration
public static ConstructAction.DefaultLength DefaultRectHeight
Field Value
| Type | Description |
|---|---|
| ConstructAction.DefaultLength |
DefaultRectWidth
The default width of a rectangle/parallelogram. Normally it is set at the end of a rectangle-constrution to the width of that rectangle, so a new rectangle/parallelogram can start with the width of the last rectangle/parallelogram by using the TAB-button within the width-textfield to accept the default width.
Declaration
public static ConstructAction.DefaultLength DefaultRectWidth
Field Value
| Type | Description |
|---|---|
| ConstructAction.DefaultLength |
DefaultRoundRadius
The default radius of the round-actions in the tools-menue. Normally it is set at the end of a round-action to current radius, so a round action can start with the radius of the last action by using the TAB-button within the roundradius-textfield to accept the default radius.
Declaration
public static ConstructAction.DefaultLength DefaultRoundRadius
Field Value
| Type | Description |
|---|---|
| ConstructAction.DefaultLength |
DefaultScaleDistort
The default way of the scale-modification of activated objects. If DefaultDistort is true, there can be different factors in the main axis, which will distort the objects
Declaration
public static ConstructAction.DefaultBoolean DefaultScaleDistort
Field Value
| Type | Description |
|---|---|
| ConstructAction.DefaultBoolean |
DefaultStartPoint
The startpoint of a line. Normally it is set at the end of a line-constrution to the endpoint of that line, so a new line can start at the endpoint of the last line by using the TAB-button within the startpoint-textfield to accept the default point.
Declaration
public static ConstructAction.DefaultGeoPoint DefaultStartPoint
Field Value
| Type | Description |
|---|---|
| ConstructAction.DefaultGeoPoint |
DefaultTextSize
The default size of the text in text constructions. Normally it is set at the end of a text construction to current size, so next text construction can start with the size of the last construction by using the TAB-button within the cut off length-textfield to accept the default length.
Declaration
public static ConstructAction.DefaultLength DefaultTextSize
Field Value
| Type | Description |
|---|---|
| ConstructAction.DefaultLength |
Methods
| Improve this Doc View SourceGetID()
Overrides GetID()
Declaration
public override string GetID()
Returns
| Type | Description |
|---|---|
| System.String |


Back to the rapture
Video version
View source
Click to play
MOUSE = Look around
W / S / A / D / Q / E = Move forward / back / left / right / down / up


In this chapter, we will mainly focus on making a “publication-type” figure, with sub-plots and such using different tools in R. There are many different ways/packages to do this, but we will mainly focus on 2 packages: cowplot
and ggpubr
.
Now let us consider some of the plots we have made so far in the previous exercises. From the picture below, A and B are the figures that was made from the gene counts
dataset and the figures C and D are using the Sepal.Length
and Sepal.Width
from the iris
data. Now let us look into how we can combine each of the figures like it is shown here.
Now, let us go step by step. First let us make these plots into R objects. This will make things a lot easier.
p1 <- gc_long %>%
group_by(Time, Replicate) %>%
summarise(mean=mean(log10(count +1)),se=se(log10(count +1))) %>%
ggplot(aes(x= Time, y= mean, fill = Replicate)) +
geom_col(position = position_dodge2()) +
geom_errorbar(aes(ymin=mean-se, ymax=mean+se), position = position_dodge2(.9, padding = .6)) +
ylab("mean(log10(count+1))") +
theme(axis.ticks = element_blank()) +
theme_bw(base_size = 10)
p2 <- ggplot(data = gc_long) +
geom_boxplot(mapping = aes(x = Sample_Name, y = log10(count + 1), fill = Replicate)) +
facet_grid(~Time , scales = "free", space = "free") +
xlab("Time") +
theme_bw(base_size = 10) +
theme(axis.ticks.x = element_blank(), axis.text.x = element_blank())
p3 <- ggplot(data=iris,mapping=aes(x=Sepal.Length))+
geom_density(aes(fill = Species), alpha = 0.6) +
theme_light(base_size = 10)
p4 <- ggplot(data=iris,mapping=aes(x=Sepal.Length, y = Sepal.Width, color = Species)) +
geom_point(size = 3, alpha = 0.6) +
theme_light(base_size = 10)
The objects p1
, p2
, p3
and p4
as intuitively represent the plots A, B, C and D repectively.
One can use the simple plot_grid()
function from the cowplot
.
You can also do some simple customizations using nrow
or ncol
to specify the number of rows and columns and provide labels
to those plots as well.
In cowplot
, you can also customize the dimentions of the plots in a much more controlled fashion. For this one starts with ggdraw()
which initiates the drawing “canvas” followed by draw_plot()
that you use to draw the different plots on to the canvas.
Here is how the dimentions of the empty canvas looks like:
From here, you can draw your plots in the way you want using these dimensions. AN example is shown below, where we plot C and D similar to the plot above:
ggdraw() +
draw_plot(p3, x = 0, y = 0, width = 1, height = .5) +
draw_plot(p4, x = 0, y = .5, width = 1, height = .5)
plot
You can also add “labels” to these figures using draw_plot_label()
with the same dimensions.
ggdraw() +
draw_plot(p3, x = 0, y = 0.5, width = 1, height = .5) +
draw_plot(p4, x = 0, y = 0, width = 1, height = .5) +
draw_plot_label(label = c("A", "B"), size = 15, x = c(0,0), y = c(1, 0.5))
plot
It is easier to draw three (or any odd number) plots in a neat way using this function compared to plot_grid()
The package ggpubr
comes with quite a few functions that can be very useful to make comprehensive figures. To start with the simple function, let’s start with ggarrange()
that is used to put plots together.
One of the nicer things with ggarrange()
is that you can automatically have common legends that are shared between the figures.
You can include tables and even normal texts to any figure using ggtexttable()
and ggparagraph()
. Let us look into adding a table that we saw in the previous exercise with the gene counts
dataset.
gc_table <- gc_long %>%
group_by(Time) %>%
summarise(mean=mean(log10(count +1)),se=se(log10(count +1)))
tab1 <- ggtexttable(gc_table, rows = NULL,
theme = ttheme("mOrange"))
gc_text <- paste("In the experiment, RNA was extracted at four time points:",
"before the gefinitib treatment (t=0), and two, six and twenty-four hours",
"after treatment (t=2, t=6, t=24, respectively).", sep = " ")
tex1 <- ggparagraph(text = gc_text, face = "italic", size = 11, color = "black")
Note Here, for the text
part, paste()
has been used just to make it a bit easier to show here in the code. It could be used without the paste()
command as well.
With ggarrange()
it is also possible to make multiple-page plots. If you are for example making a report of many different figures this can come quite handy. Then you can use ggexport()
to export these figures in a multi-page pdf
.
Note From this multi.page
R object (which is of class list) , you can get the indivdual plots by multi.page[[1]]
, multi.page[[2]]
and so on.
Task For the exercise in this session, let us look into way of using the tools available for combining plots to make one plot that could be very comprehensive. Try to code the figure below:
Tip: 1 Within ggarrange()
, it is possible to adjust the dimension of each plot with widths
and heights
options.
Tip: 2 You can plot an empty plot with NULL
.
## R version 3.6.3 (2020-02-29)
## Platform: x86_64-pc-linux-gnu (64-bit)
## Running under: Ubuntu 20.04.1 LTS
##
## Matrix products: default
## BLAS: /usr/lib/x86_64-linux-gnu/blas/libblas.so.3.9.0
## LAPACK: /usr/lib/x86_64-linux-gnu/lapack/liblapack.so.3.9.0
##
## locale:
## [1] LC_CTYPE=en_US.UTF-8 LC_NUMERIC=C
## [3] LC_TIME=en_US.UTF-8 LC_COLLATE=en_US.UTF-8
## [5] LC_MONETARY=en_US.UTF-8 LC_MESSAGES=en_US.UTF-8
## [7] LC_PAPER=en_US.UTF-8 LC_NAME=C
## [9] LC_ADDRESS=C LC_TELEPHONE=C
## [11] LC_MEASUREMENT=en_US.UTF-8 LC_IDENTIFICATION=C
##
## attached base packages:
## [1] stats graphics grDevices utils datasets methods base
##
## other attached packages:
## [1] ggpubr_0.4.0 cowplot_1.1.0 forcats_0.5.0 stringr_1.4.0
## [5] purrr_0.3.4 readr_1.3.1 tidyr_1.1.2 tibble_3.0.4
## [9] tidyverse_1.3.0 reshape2_1.4.4 ggplot2_3.3.2 dplyr_1.0.2
## [13] captioner_2.2.3 bookdown_0.20 knitr_1.29
##
## loaded via a namespace (and not attached):
## [1] Rcpp_1.0.5 lubridate_1.7.9 assertthat_0.2.1 digest_0.6.27
## [5] R6_2.5.0 cellranger_1.1.0 plyr_1.8.6 backports_1.1.10
## [9] reprex_0.3.0 evaluate_0.14 httr_1.4.2 pillar_1.4.6
## [13] rlang_0.4.8 curl_4.3 readxl_1.3.1 rstudioapi_0.11
## [17] data.table_1.13.2 car_3.0-9 blob_1.2.1 rmarkdown_2.3
## [21] labeling_0.4.2 foreign_0.8-75 munsell_0.5.0 broom_0.7.0
## [25] compiler_3.6.3 modelr_0.1.8 xfun_0.18 pkgconfig_2.0.3
## [29] htmltools_0.5.0 tidyselect_1.1.0 gridExtra_2.3 rio_0.5.16
## [33] fansi_0.4.1 crayon_1.3.4 dbplyr_1.4.4 withr_2.3.0
## [37] grid_3.6.3 jsonlite_1.7.1 gtable_0.3.0 lifecycle_0.2.0
## [41] DBI_1.1.0 magrittr_1.5 scales_1.1.1 zip_2.1.0
## [45] carData_3.0-4 cli_2.1.0 stringi_1.5.3 farver_2.0.3
## [49] ggsignif_0.6.0 fs_1.5.0 xml2_1.3.2 ellipsis_0.3.1
## [53] generics_0.0.2 vctrs_0.3.4 openxlsx_4.1.5 tools_3.6.3
## [57] glue_1.4.2 hms_0.5.3 abind_1.4-5 yaml_2.2.1
## [61] colorspace_1.4-1 rstatix_0.6.0 rvest_0.3.6 haven_2.3.1
End of document


Superhero request form
What do you need help with?
DEFEAT A VILLAIN
SAVE A CIVILIAN
STOP A ROBBERY
PREVENT AN APOCALYPSE
TRAIN A SIDEKICK
OTHER STUFF
SEND


Page Not Found
Login
Register
Looks like this was not the page you were looking for!
LoL Mastery Battle!


Music (Bluegrass & Americana), Wooden Spoon Carving, Cooking, Microelectronics (Arduino & Raspberry Pi), Computer Programming
Music (Bluegrass & Americana), Wooden Spoon Carving, Cooking, Microelectronics (Arduino & Raspberry Pi), Computer Programming
Microsoft Word, Excel, HTML/CSS
PHP, Python, & MySQL
R, CouchDB, & Javascript


Distributed Web of Care
Announcing Call for Deaf or Disabled Stewards
Update May 2019: Applications for this particular call are no longer open, however if you are interested in collaborating with the project please reach out.
Distributed Web of Care (DWC) is a collaboration between artists, writers and engineers to imagine a more equitable, caring internet for the future. The project is initiated by Taeyoon Choi, who has been working with disability community and artists to criticially challenge the notions of accessibility and inclusion. Read his article Artificial Advancement and Shannon Finnegan’s article Accessibility Dreams.
In February - March 2019, we are looking for stewards who identify as a Deaf or disabled person. We are planning a large scale participatory performance art in the end of March. The event will have ASL interpretation and audio description. We would like to work with stewards who identify as a Deaf or Disabled person to create an inclusive and welcoming experience for the disability community.
Decentralized Web Summit, The Internet Archive/San Fransisco Mint, 2018
M+ Matters: Art and Design in the Digital Realm, M+/Tai Kwun, Hong Kong, 2018
Refiguring the Future, Eyebeam/REFRESH, Knockdown Center, 2019
From February to March 2019, we are planning a large scale participatory performance art in the end of March. The event will be wheelchair accessible, and will have ASL interpretation and audio description. We would like to work with stewards who identify as a Deaf or disabled person to create an inclusive and welcoming experience for the disability community.
Stewards are guest collaborators who contribute to DWC initiatives with their domain expertise. Stewards are invited to rehearsals for DWC events and contribute to building the piece as well as code of conduct. In this volunteer role, stewards will collaborate with fellow artists, engineers, organizers, staff and with Taeyoon Choi directly.
DWC is a movement activity which involves strings and other props, sound and visuals, which requires assistance of stewards to help other participants in the movement activity stay safe. We are asking for stewards to join a rehearsal and the final performance to help the choreographer and other stewards make space for people who identify as disabled to feel welcome, secure and comfortable.
In our efforts to imagine the future of the internet, we hope to create an inclusive and equitable experience for everyone, however, we understand the impossibility of this as there may be conflict of access needs. In order to be prepared for all contingencies, we are inviting the disability community to be a part of planning and execution of the project. We also hope to avoid creating an unintentionally exclusive experience, therefore stewards mentorship and guidance will help us create a better experience for everyone attending the event.
The rehearsal dates are March 3, 2-5 PM and March 25, 2-5 PM, 2019 in wheelchair accesible locations in Manhattan, NYC.
Apply or email<EMAIL_ADDRESS>Equal opportunity: Distributed Web of Care is committed to providing an environment that is free from discrimination and harassment based on race, age, creed, color, religion, national origin or ancestry, sex, gender, disability, veteran status, genetic information, sexual orientation, gender identity or expression, or pregnancy.
Distributed Web of Care is an initiative to code to care and code carefully.
The project imagines the future of the internet and consider what care means for a technologically-oriented future. The project focuses on personhood in relation to accessibility, identity, and the environment, with the intention of creating a distributed future that’s built with trust and care, where diverse communities are prioritized and supported.
The project is composed of collaborations, educational resources, skillshares, an editorial platform, and performance. Announcements and documentation are hosted on this site, as well as essays by select artists, technologists, and activists.
-
Jan 4, 2022
garden.local
-
Jun 7, 2020
Community Over Commodity
-
Mar 18, 2020
Oddkins
-
Oct 10, 2019
New Merchandise
-
Aug 10, 2019
Announcing Decentralized Networks Workshop
-
May 24, 2019
On Stewardship
-
May 23, 2019
Movement Scores
-
May 4, 2019
Who Owns the Stars: The Trouble with Urbit
-
May 1, 2019
Announcing WYFY School with BUFU
-
Mar 5, 2019
Announcing Lecture Performance at the Whitney Museum
-
Feb 25, 2019
Announcing Call for Deaf or Disabled Stewards
-
Feb 7, 2019
Making Space in Online Archives
-
Jan 29, 2019
Accessibility Dreams
-
Jan 28, 2019
Creative Self Publishing
-
Jan 11, 2019
Racial Justice in the Distributed Web
-
Dec 29, 2018
Announcing LACA Residency
-
Dec 28, 2018
Announcing DWC at Code Societies
-
Dec 21, 2018
Building a Museum 353 Years in the Future
-
Sep 11, 2018
Finding Intimacy within Black Feminist Criticism
-
Jul 26, 2018
still stuck with words
-
Jul 26, 2018
Distributed Dance Floor
-
Jun 27, 2018
Announcing Skillshares: Peers in Practice
-
Jun 27, 2018
Announcing the Distributed Web of Care Party
-
Jun 27, 2018
Communities and New Infrastructures
-
Jun 27, 2018
New Gardens
-
May 20, 2018
Announcing Summer 2018 Fellows
-
Apr 28, 2018
DWC Merchandise: Care Shirt & Hoodie
-
Apr 27, 2018
Announcing Artists in Residence at Ace Hotel New York
-
Apr 18, 2018
Documentation: Ethics and Archiving the Web
-
Apr 18, 2018
Call for Fellows and Stewards
-
Apr 17, 2018
Code of Conduct
-
Mar 18, 2018
About
-
Distributed Web of Care


I am a Web developer with enthusiasm and currently focused on React and MERN stack.
I love web programming and besides front end I also know backend programming. For detailed information about me and my education visit my Linkedin profile and for projects my Github profile.
Feel free to contact me via email at any time
FullApp worked with NodeJS, Express, MongoDB and EJS temlateing engine.
React app to search Github profiles. This app uses the Context API along with the useContext and useReducer hooks for state
Project of creating an online shop application. The project integrates php programming, My SQL Database, Java Script and Web Design HTML and CSS
Final project of the Front end developer course of the Krojac school, done from design to code
Bank application that worked in HTML5, CSS3 and vanilla JS with basic CRUD operations
Would you like to work with me? Awesome!
Let's build together!


Intermediate representation used by MEnv during compilation.
Written by Edwin Olson (ebolson@umich.edu)


The Resource Centre provides reference library service on tobacco control for the general public. The collections include books, audio-videos materials, research papers, conference proceedings, reference kits on the hazards of tobacco smoking, secondhand smoke, tobacco control legislations and development of tobacco control in recent decades of Hong Kong. Visitors of Resource Centre include students, teachers, parents, researchers and oversea delegations on public health and tobacco control, medical and health practitioners as well as the general public.
Address: Unit 4402-03, 44/F, Hopewell Centre, 183 Queen’s Road East, Wanchai, Hong Kong
Tel: +852 2838 8822
Email<EMAIL_ADDRESS>Opening hours: Monday to Friday) 9:30am - 12:00pm ; 2:30pm - 5:00pm (Saturdays, Sundays and Public Holidays closed.)


tagger package¶
Subpackages¶
Submodules¶
tagger.asg_tagger module¶
ASG tagger module
This module is deployed as a Lambda function within an AWS Environment. This function is responsible for tagging AutoScaling Groups at creation with the email associated with the account creating the group. It also tags the group’s instances and ensures future instances will inherit the tags.
Note
The function expects specific AWS Event Data, passed through the event parameter. It supports one event referring to the creation of an AutoScaling Group:
- CreateAutoScalingGroup
-
class
tagger.asg_tagger.
ASGTagger
(event, context)¶ Bases:
object
Class used to tag AutoScaling Groups and it’s instances
-
region
¶ AWS Region the Lambda resides in
Type: str
-
session
¶ boto3 object for AWS Session
Type: obj
-
ec2
¶ abstracts AWS ASG calls via ASGWrapper
Type: obj
-
event
¶ event object passed by lambda_handler
Type: dict
-
context
¶ context object passed by lambda_handler
Type: dict
-
parser
¶ Class used to parse the event dictionary
Type: obj
-
start
()¶ Tagger entry point
This method is called by the lambda handler. It parses the event and tags the appropriate resources.
Returns: Response from AWS CreateOrUpdateTags API Call Return type: dict
-
-
tagger.asg_tagger.
lambda_handler
(event, context)¶ Lambda entry point
This is the handler associated with this lambda function. It instantiates a new ASGTagger and passes down the event data.
Parameters: - event (dict) – Event dictionary passed by AWS
- context (dict) – Context dictionary passed by AWS (not used but required by AWS)
Returns: Response from AWS CreateOrUpdateTags API Call
Return type: dict
tagger.ec2_tagger module¶
EC2 tagger module
This module is deployed as a Lambda function within an AWS Environment. This function is responsible for tagging EC2 instances/resources at creation with the email associated with the account creating the instance/resource.
Note
The function expects specific AWS Event Data, passed through the event parameter. It supports four events, each referring to a supported resource:
- RunInstances
- CreateSecurityGroup
- CreateVolume
- CreateImage
-
class
tagger.ec2_tagger.
EC2Tagger
(event, context)¶ Bases:
object
Class used to tag EC2 Resources
-
region
¶ AWS Region the Lambda resides in
Type: str
-
session
¶ boto3 object for AWS Session
Type: obj
-
ec2
¶ abstracts AWS EC2 calls via EC2Wrapper
Type: obj
-
event
¶ event object passed by lambda_handler
Type: dict
-
context
¶ context object passed by lambda_handler
Type: dict
-
parser
¶ Class used to parse the event dictionary
Type: obj
-
start
()¶ Tagger entry point
This method is called by the lambda handler. It parses the event and tags the appropriate resources.
Returns: Response from AWS CreateTags API Call Return type: dict
-
-
tagger.ec2_tagger.
lambda_handler
(event, context)¶ Lambda entry point
This is the handler associated with this lambda function. It instantiates a new EC2Tagger and passes down the event data.
Parameters: - event (dict) – Event dictionary passed by AWS
- context (dict) – Context dictionary passed by AWS (not used but required by AWS)
Returns: Response from AWS CreateTags API Call
Return type: dict


A simple Hoare triple prover
Feb 6, 2020 00:00 · 3238 words · 16 minute read
Introduction: what is Hoare logic?
First steps
According to wikipedia:
Hoare logic (also known as Floyd–Hoare logic or Hoare rules) is a formal system with a set of logical rules for reasoning rigorously about the correctness of computer programs.
So this is a powerful system that let us reason formally about the correctness of our program. The basic structure of Hoare logic is the Hoare triple. A triple describes how some properties of the state are modified by the execution of a program. A triple has the form of
\[ \{P\}C\{Q\}\]
where \(P\) and \(Q\) are assertions and \(C\) is a program. \(P\) is called precondition and \(Q\) is called postcondition. A triple is said valid if, for each states that satisfies the precondition, the program terminates and the resulting state satisfies the postcondition.
I use a custom language for writing the program, that supports only empty statements, assignments, composition, if statemets and while statement. I'm sure you will have no problem following the syntax of this language as it is fairly standard.
Examples of valid triples are:
\[\{x=0\}x:=x+1\{x=1\}\]
This triple is valid because if before the execution it holds that \(x=0\), then after the execution of the assignment command the assertion \(x=1\) will hold as well. An important condition for the validity of a triple is the termination, but since the command is an assignment, it always terminates (except for when we have an undefined expression on the right hand side, like \(x/0\), but for simplicity we will just assume that the program we will write will never try to evaluate an undefined expression).
\[\{ x=A \land y=B\}z:=x; x:=y; y:=z\{x=B \land y=A\}\]
This is a variable swap, notice that this triple is completely parametric, as it uses two constants (\(A\) and \(B\)) that stand for arbitrary values. This is a very powerful thing you can do in Hoare logic, as this triple is valid for all values of \(x\) and \(y\).
But we can have even more complicated triples, such as
\[\{s=\sum_{k=0}^i k^2\}i:=i+1;s:=s+i*i\{s=\sum_{k=0}^i k^2\}\]
or
\[\{n \geq 1\}\\\text{while}(n \neq 1) \text{do if} (n \text{ mod } 2 = 0) \text{ then } n:=n/2\text{ else } n:= 3n+1 \text{ fi endw}\\\{n=1\}\]
you may have recognized this triple, as it is valid iff the Collatz conjecture is true. Also this is an example where proving just the termination of the command is very important and not trivial at all (in fact, proving the termination is sufficient for proving the entire triple).
What is an inference rule?
I'm sure if you are reading this, that you will be familiar with the concept of inference, but just to make sure we are all on the same page and to make clear the notation used, it's best to discuss this important concept.
An inference rule has the form
\[\frac{\phi_1 \quad \phi_2 \quad \phi_3 \quad \dots \quad \phi_n}{\phi}\]
where \(\phi_1 \dots \phi_n\) are the premises and \(\phi\) is the conclusion. This can be read in two ways:
- if \(\phi_1 \dots \phi_n\) are all valid formulas, then we can infer (or derive) the formula \(\phi\)
- to prove \(\phi\) it is sufficient to prove that \(\phi_1 \dots \phi_n\) are all valid formulas.
For our purpose, the second interpretetion is what fits the best, so keep in mind this intuition behind inference rules.
An axiom is just an inference rule with no premises, so that if \(\psi\) is an axiom we will write
\[\frac{}{\psi}\]
Examples of inference rules in classical propositional calculus are
\[\frac{A \land B}{A}\quad (\land \text{ elimination})\]
\[\frac{A \to B \quad \neg B }{\neg A}\quad \text{(Modus Tollens)}\]
For example, the last one in our interpretation is read "to prove that \(\neg A\) is valid it is sufficient to prove that \(A \to B\) and \(\neg B\) are both valid".
A proof system for Hoare triples
Axioms
Now let's discuss about how to formally prove that a triple is valid. Let's start with some axioms: these are basic triples that are always valid.
The first axiom is the empty command axiom (or skip axiom):
\[\frac{}{\{P\}\text{skip}\{P\}}\quad (\text{SKIP-AX})\]
where \(P\) is an arbitrary assertion and \(\text{skip}\) is the empty command. The intuition behind this axiom is that if a certain condition holds before the skip statement, then it will also hold after the execution, because skip does not modify the state and always terminates.
The second axiom is the assignment axiom:
\[\frac{}{\{P[x \mapsto E]\}x:=E\{P\}}\quad (\text{ASSIGNMENT-AX})\]
where \(P[x \mapsto E]\) means the assertion \(P\) with all the occurrences of \(x\) replaced by \(E\). The intuition behind this axiom is that if an assertion must hold true after the assignment statement, then it must hold also before the statement, but with the identifier substituted by the expression.
Basic inference rules
Now, let's talk about some serious stuff: inference rules. The first one is pretty straight forward, and it is the pre-post rule:
\[\frac{P\to P' \quad \{P'\}C\{Q'\} \quad Q' \to Q}{\{P\}C\{Q\}}\quad \text{(PRE-POST)}\]
The intuition behind this rule is that we can strengthen the precondition and we can weaken the postcondition at our favor.
This rule is really important because with this and the two axioms we can derive the second and the third inference rules:
\[\frac{P \to Q}{\{P\}\text{skip}\{Q\}}\quad (\text{SKIP})\]
\[\frac{P \to Q[x \mapsto E]}{\{P\}x:=E\{Q\}}\quad (\text{ASSIGNMENT})\]
The next rule is the composition rule (or sequence rule):
\[\frac{\{P\}C_1\{R\} \quad \{R\}C_2\{Q\}}{\{P\}C_1;C_2\{Q\}}\quad (\text{COMPOSITION})\]
The intuition behind this rule is that if it can be found an intermediate assertion (in this case \(R\)) so that the two single triples are valid, then the whole triple is also valid.
Contditional and while rules
Now let's see the most difficult rules: the if and the while rules. Let's start with the conditional one:
\[\frac{\{P \land E\}C_1\{Q\} \quad \{P \land \neg E\}C_2\{Q\}}{\{P\}\text{if } E \text{ then } C_1 \text{ else } C_2\{Q\}}\quad (\text{IF})\]
The intuition behind this rule is that we have to prove the triple both in the case that the guard is satisfied and in the case that it is not satisfied, so that in the general case the triple holds. This rule remembers me the proof by cases in propositional calculus, that is:
\[\frac{P \to Q \quad \neg P \to Q}{Q}\quad \text{Proof by cases}\]
but I'm digressing.
Let's talk about the while rule. I'm ging to present this monstruosity so that we can then break it down piece by piece:
\[\frac{\begin{gathered} P \to inv \quad inv \to Q \quad inv \to t \geq 0 \\\{inv \land E\}C\{inv\} \quad \{inv \land E \land t=V\}C\{ t \lt V \} \end{gathered}}{\{P\}\text{while }E \text{ do } C \text{ endw}\{Q\}}\quad \text{(WHILE)}\]
Ok, so, take a deep breath, because this will be kind of a long one. The semantics of the while command is just a composition of the same command (that is the body of the while). So the semantics of the while can be expanded as follows:
\[\overbrace{C;C;C;C;C \dots C}^{n \text{ times}}\]
where \(n\) is the number of times the body of the while will be executed. Notice that the guard may never become false, in that case the sequence of commands is infinite. To prove that this command terminates and the sequence of commands is finite, we assign a natural number (which is identified by the expression \(t\)) to each cycle, so that we create a sequence. Now to prove that this sequence terminates we just have to prove that this sequence is strictly decreasing (we use a theorem that states that every strictly decreasing sequence of natural numbers is finite).
To do this we can use a thing called loop invariant (often called only \(inv\)), that is an assertion that is true at the beginning of every iteration. With this we can prove the termination and also we can be sure that the precondition and postcondition are satisfied.
Now, with everithig settled in, let's discuss in some detail the 5 premises of the while rule:
- \(\{inv \land E\}C\{inv\}\): this is called the invariance premise, as it makes sure that the \(inv\) assertion is true at the beginning of each iteration.
- \(P \to inv\): this is called the pre premise, as is simply make sure that the precondition is stronger than the invariant, so that the first time we enter the loop, the invariant holds.
- \( inv \to Q\): this is called post premis, and as the name sugest make sure that the if the invariant is true, then also the postcondition is true. This is done so that at the end of the execution we can make sure that the postcondition holds true, since we know that the invariant holds true.
- \(\{inv \land E \land t=V\}C\{ t \lt V \}\): this is called progress premise, as it make sure that each term of the sequence is strictly decreasing.
- \(inv \to t\geq 0\): last but not least the termination premise, that make sure that our sequence identified by the expression \(t\) has a lower bound, in this case 0, so that we can make sure it is finite.
Whoa! That was quite a jurney! But now let's stop talking about theory and let's jump into the code!
The automatic theorem prover
Premises
For this project I choose python as the main language because I was not aiming at a full-fledged and efficient prover, but more at a proof-of-concept or prototype program, in which python is really great. In particular I used z3 theorem prover for proving the implications, and lark for parsing the input triple. The whole project is on github, pull requests are welcome!
The parser
Using lark, parsing was surprisingly easy. I just defined the grammar into a big string and lark taked care of everything. The grammar can be seen in the source code for the parser. An example triple that can be accepted by the parser is:
[x, A]
{x==A}
x := x-3;
if (x >= 0) then
x := x + 5
else
x := -x + 5
fi
{x>A}
In the first line we declare all the identifiers that we are going to use in the triple. Then we state the precondition, the command and the postcondition. The triple procesed by the parser produces a parse tree, which is perfect because we will do a lot of induction on the structure of the program.
The prover
The basic building block for the theorem prover is a function that takes in input a z3 formula and tries to prove the validity of if. This is implemented as follows.
def prove_formula(self, what_to_prove):
s = z3.Solver()
s.add(z3.Not(what_to_prove))
res = s.check()
if str(res) == "unsat":
print("proved", what_to_prove)
return True
else:
print("could not prove", what_to_prove)
return False
The z3's check function can only give you 2 results: sat
, which means that the formula is satisfiable, and unsat
, which means the formula is unsatisfiable. So there is no result for valid, but we can use a well known fact in logic: a formula \(\phi\) is valis iff \(\neg \phi\) is unsatisfiable. So we negate the formula and if it is unsatisfiable, then the formula is considered proved.
Now let's start implementing the main protagonist of this jurney: the prove_triple()
function, that takes in input a precondition as a z3 formula, a command as a parse tree and a postcondition as a z3 formula and returns True if the triple is valid, False otherwise. The first inference rule we will implement is the simplest one: the skip rule.
\[\frac{P \to Q}{\{P\}\text{skip}\{Q\}}\quad (\text{SKIP})\]
def prove_triple(self, precond, command, postcond):
if command.data == "skip":
formula_to_prove = z3.Implies(precond, postcond)
print("found skip statement, trying to prove", formula_to_prove)
res = self.prove_formula(formula_to_prove)
return res
Here we state that for proving a skip triple it is sufficient to prove that the precondition implies the postcondition.
Now let's implement the assignment inference rule.
\[\frac{P \to Q[x \mapsto E]}{\{P\}x:=E\{Q\}}\quad (\text{ASSIGNMENT})\]
elif command.data == "assignment":
ide, exp = command.children
formula_to_prove = z3.Implies(
precond,
z3.substitute(postcond, (self.env[ide], self.expr_to_z3_formula(exp)))
)
print("found assignment statement, trying to prove", formula_to_prove)
res = self.prove_formula(formula_to_prove)
return res
Now let's go on and implement the conditional inference rule. This is when prove_triple
becomes inductive, as it calls itself on a subtree of the parse tree.
\[\frac{\{P \land E\}C_1\{Q\} \quad \{P \land \neg E\}C_2\{Q\}}{\{P\}\text{if } E \text{ then } C_1 \text{ else } C_2\{Q\}}\quad (\text{IF})\]
elif command.data == "if":
guard, s1, s2 = command.children
print("found if statement, trying to prove the first alternative")
res_1 = self.prove_triple(z3.And(precond, self.expr_to_z3_formula(guard)), s1, postcond)
if res_1:
print("now trying to prove the second alternative")
res_2 = self.prove_triple(z3.And(precond, z3.Not(self.expr_to_z3_formula(guard))), s2, postcond)
return res_2
else:
return False
There is nothing magical in the code yet: these three cases are the direct translation of the inference rule.
Now let's talk about composition. From the inference rule we know we have to search for an intermediate assertion, so that both intermediate triples are valid.
\[\frac{\{P\}C_1\{R\} \quad \{R\}C_2\{Q\}}{\{P\}C_1;C_2\{Q\}}\quad (\text{COMPOSITION})\]
There is no rule on how to find it, but we can use some heuristics to find it. Basically we try to find an assertion \(R\) so that \(\{R\}C_2\{Q\}\) is an axiom (so is valid in our proof system) and then we delegate the validity of the whole triple to the validity of \(\{P\}C_1\{R\}\). To do this we need a new function called find_axiom that takes in input a command as a parse tree and a postondition as a z3 formula and tries to find a precondition so that the triple is an axiom. Remember that there are only two axioms in our system, so we can implement only them.
\[\frac{}{\{P\}\text{skip}\{P\}}\quad (\text{SKIP-AX})\]
\[\frac{}{\{P[x \mapsto E]\}x:=E\{P\}}\quad (\text{ASSIGNMENT-AX})\]
def find_axiom(self, command, postcond):
if command.data == "skip":
print("found axiom for skip statement:", postcond)
return (True, postcond)
elif command.data == "assignment":
ide, exp = command.children
axiom = z3.substitute(postcond, (self.env[ide], self.expr_to_z3_formula(exp)))
print("found axiom for assignment statement:", axiom)
return (True, axiom)
else:
print("could not find axiom")
return (False, None)
Now we are all set for implementing the composition rule.
\[\frac{\{P\}C_1\{R\} \quad \{R\}C_2\{Q\}}{\{P\}C_1;C_2\{Q\}}\quad (\text{COMPOSITION})\]
elif command.data == "composition":
c1, c2 = command.children
print("found composition, trying to find axiom for the right side")
(res, axiom) = self.find_axiom(c2, postcond)
if res:
return self.prove_triple(precond, c1, axiom)
else:
return False
With theese simple inference rules implemented, we can try our prover on a variable swap. So the input triple looks like this:
[x, y, z, A, B]
{x==A and y==B}
z := x;
x := y;
y := z
{x==B and y==A}
The output of our prover is:
What to prove: [x, y, z, A, B]
{x==A and y==B}
z := x;
x := y;
y := z
{x==B and y==A}
found composition, trying to find axiom for the right side
found axiom for assignment statement: And(x == B, z == A)
found composition, trying to find axiom for the right side
found axiom for assignment statement: And(y == B, z == A)
found assignment statement, trying to prove Implies(And(x == A, y == B), And(y == B, x == A))
proved Implies(And(x == A, y == B), And(y == B, x == A))
The triple is valid
Yay! So the verdict is that this triple is valid! That means that so far our little prover works! The great thing is that you can see the process of the program by looking at the output, and we can see that the steps made by our little program are exactly what we expected.
Now we just have to implement the scary one: the while inference rule. Luckly we got the hang of it, and now the code is pretty much a direct application of the inference rule.
\[\frac{\begin{gathered} P \to inv \quad inv \to Q \quad inv \to t \geq 0 \\\{inv \land E\}C\{inv\} \quad \{inv \land E \land t=V\}C\{ t \lt V \} \end{gathered}}{\{P\}\text{while }E \text{ do } C \text{ endw}\{Q\}}\quad \text{(WHILE)}\]
elif command.data == "while":
e, t_expr, inv, c = command.children
print("found while statement, trying to prove:")
invariant = self.expr_to_z3_formula(inv)
t = self.expr_to_z3_formula(t_expr)
guard = self.expr_to_z3_formula(e)
pre = z3.Implies(precond, invariant)
post = z3.Implies(z3.And(precond, z3.Not(guard)), postcond)
term = z3.Implies(z3.And(invariant, self.env["t"] == t), t>=0)
print("1) [pre]", pre)
res_pre = self.prove_formula(pre)
if res_pre:
print("2) [post]", post)
res_post = self.prove_formula(post)
if res_post:
print("3) [term]", term)
res_term = self.prove_formula(term)
if res_term:
print("4) [invariance]", term)
res_inv = self.prove_triple(z3.And(invariant, guard), c, invariant)
if res_inv:
print("5) [progress]", term)
v = z3.Int("V")
res=self.prove_triple(
z3.And(z3.And(invariant, guard), t==v),
c,
t<v
)
return res
return False
So now we can finally prove some simple while triples! I have added some syntax to the while command to code the loop invariant and the expression for \(t\). Here's an example triple that calculates \(5 \cdot 10\) in a very stupid way:
[i, s, t, r]
{i==0 and r==0}
while (i<10) where t is (10-i); inv is (r==5*i and 10-i>=0) do
i := i+1;
r := r+5
endw
{r==5*10}
This time the output is a bit more cluttered:
What to prove: [i, s, t, r]
{i==0 and r==0}
while (i<10) where t is (10-i); inv is (r==5*i and 10-i>=0) do
i := i+1;
r := r+5
endw
{r==5*10}
found while statement, trying to prove:
1) [pre] Implies(And(0 == i, 0 == r), And(r == 5*i, 0 <= 10 - i))
proved Implies(And(0 == i, 0 == r), And(r == 5*i, 0 <= 10 - i))
2) [post] Implies(And(And(0 == i, 0 == r), Not(10 > i)), r == 5*10)
proved Implies(And(And(0 == i, 0 == r), Not(10 > i)), r == 5*10)
3) [term] Implies(And(And(r == 5*i, 0 <= 10 - i), t == 10 - i),
10 - i >= 0)
proved Implies(And(And(r == 5*i, 0 <= 10 - i), t == 10 - i),
10 - i >= 0)
4) [invariance] Implies(And(And(r == 5*i, 0 <= 10 - i), t == 10 - i),
10 - i >= 0)
found composition, trying to find axiom for the right side
found axiom for assignment statement: And(r + 5 == 5*i, 0 <= 10 - i)
found assignment statement, trying to prove Implies(And(And(r == 5*i, 0 <= 10 - i), 10 > i),
And(r + 5 == 5*(i + 1), 0 <= 10 - (i + 1)))
proved Implies(And(And(r == 5*i, 0 <= 10 - i), 10 > i),
And(r + 5 == 5*(i + 1), 0 <= 10 - (i + 1)))
5) [progress] Implies(And(And(r == 5*i, 0 <= 10 - i), t == 10 - i),
10 - i >= 0)
found composition, trying to find axiom for the right side
found axiom for assignment statement: 10 - i < V
found assignment statement, trying to prove Implies(And(And(And(r == 5*i, 0 <= 10 - i), 10 > i),
10 - i == V),
10 - (i + 1) < V)
proved Implies(And(And(And(r == 5*i, 0 <= 10 - i), 10 > i),
10 - i == V),
10 - (i + 1) < V)
The triple is valid
Great! We can see exactly that all 5 while premises have been proved, so it is fair to say that this loop has been proven formally that it terminates and r will contain the result of \(5 \cdot 10\).
To experiment with this simple system (and maybe contribute to it) you can clone the repository, and you can run an example proof (for example the variable swap one) by:
$ python src/lpp_prover.py examples/var_swap.lpp
In the examples folder on github there are a bunch of triples that should give you the feeling of the capability of this system.
Conclusions
This was a very interesting project for me, because it game me the possibility to apply all this theoretical stuff I learned at university. This is not, and does not aim to be a professional formal prover, it is just a little program written by a bored cs student.


abstract fun dumpCheckpoints(): Unit
Dump all the current flow checkpoints as JSON into a zip file in the node's log directory.


Remapping Dataset¶
Datasets created by pywgrib2_xr can be remapped to cover smaller area.
This might be important to save on storage or compute time. For forecast
verification model data is compared to observations at a finite set of points.
The interpolation methods are provided by xarray dataset_accessor wgrib2
.
Interpolation to grid¶
To interpolate to a new grid, one has to define first that grid parameters.
pywgrib2_xr provides two functions: grid_fromdict()
and grid_fromstring()
. The latter follows
wgrib2 style
and is easier to use. The argument is a single string (unlike three passed to
wgrib2) which specifies projection type and basic parameters. Additional,
optional arguments allow to specify vector orientation and Earth shape.
To obtain the neccessary values from a grid in a GRIB2 file, run wgrib2
with the arguments -V -radius
:
wgrib2 data/CMC_glb_WIND_TGL_10_ps30km_2020012500_P000.grib2 -end -V -radius
1:0:vt=2020012500:10 m above ground:anl:UGRD U-Component of Wind [m/s]:
ndata=49400:undef=0:mean=0.943856:min=-22.8:max=22.5
grid_template=20:winds(grid):
polar stereographic grid: (247 x 200) input WE:SN output WE:SN res 8
North pole lat1 32.549114 lon1 225.385728 latD 60.000000 lonV 249.000000 dx 30000.000000 m dy 30000.0
:code3.2=6 sphere predefined radius=6371229.0 m
The format for polar stereographic grid is nps:lov:lad lon0:nx:dx lat0:ny:dy
.
For the above grid the first argument would be
nps:249:60 225.385728:247:30000 32.549114:200:30000
.
Since the argument winds
defaults to ‘grid’. Earth shape is the same as NCEP
default, only one argument is needed.
iplib provides five interpolation methods: nearest neighbour, bilinear, bicubic, budget and spectral. Unfortunately, there is no official documentation describing the algorithms. Few hints based on experience:
nearest neighbour: use for categorical, surface variables if you are going to look at the surface budgets, and properties.
bilinear: fast and ok for similar scale interpolations. Bad for high-res -> low-res. for example reducing 1000x1000 grid to 100x100 (same area, lower resolution). Will pick up small scale noise and reduce the forecast skill.
bicubic: theoretically more precise than bilinear, but it may introduce negative values where none exist. Not recommended.
budget: it does 25 bilinear interpolations on a 5x5 grid and computes the average. Use on precipitation fields to retain global average precipation. Also good for going from 1000x1000 -> 100x100 grid. See Accadia et al.
spectral: with the right parameters, can be the most accurate method. Like bicubic, can create negative values where none exist. Not to be used for snow, precipitation, relative humidity or surface pressure (ringing?).
See also the wgrib2 documentation on the argument -new_grid.
The following code extracts 3-hour accumulated precipitation, surface model elevation, ceiling and heights at pressure levels, within a smaller area. The data variables are renamed before remapping.
pywgrib2_xr allows interpolation type to depend on variable. The specification
is a dictionary: variable -> interpolation_type
. The default
entry is for
all remaining variables, in this case elev
and height
.
from datetime import timedelta
import pywgrib2_xr as pywgrib2
from pywgrib2_xr.utils import remotepath
file = remotepath('nam.t00z.awak3d06.tm00.grib2')
grid_desc = 'nps:225:60 227:40:8000 57:40:8000'
def pcp_pred(i):
return i.varname in ['APCP', 'ACPCP'] and \
i.end_ft - i.start_ft == timedelta(hours=3)
def elev_pred(i):
return i.varname == 'HGT' and i.level_str == 'surface'
def ceil_pred(i):
return i.varname == 'HGT' and i.level_str == 'cloud ceiling'
def height_pred(i):
return i.varname == 'HGT' and i.level_code == 100
template = pywgrib2.make_template(file, pcp_pred, elev_pred, ceil_pred,
height_pred, vertlevels='isobaric')
names = {'APCP.surface.3_hour_acc': '3h_pcp',
'ACPCP.surface.3_hour_acc': '3h_cum_pcp',
'HGT.surface': 'elev',
'HGT.cloud_ceiling': 'ceil',
'HGT.isobaric': 'height',
}
ds = pywgrib2.open_dataset(file, template).rename(names)
iptype = {'3h_pcp': 'budget',
'3h_conv_pcp': 'budget',
'ceil': 'neighbour',
'default': 'bilinear',
}
new_grid = pywgrib2.grid_fromstring(grid_desc)
ds_grd = ds.wgrib2.grid(new_grid, iptype=iptype)
ds_grd.coords['polar_stereographic'].attrs
{'grid_mapping_name': 'polar_stereographic',
'straight_vertical_longitude_from_pole': 225.0,
'standard_parallel': 60.0,
'latitude_of_projection_origin': 90.0,
'shape': 'sphere',
'earth_radius': 6371229.0,
'code': 6,
'GRIB_gdtnum': <GDTNum.POLAR_STEREO: 20>,
'GRIB_gdtmpl': [6,
0,
0,
0,
0,
0,
0,
553,
425,
30000000,
187000000,
56,
60000000,
225000000,
11250000,
11250000,
0,
64],
'GRIB_Npts': 235025,
'GRIB_Nx': 553,
'GRIB_Ny': 425,
'GRIB_La1': 30.0,
'GRIB_Lo1': 187.0,
'GRIB_LaD': 60.0,
'GRIB_LoV': 225.0,
'GRIB_winds': 'grid',
'GRIB_Dx': 11250.0,
'GRIB_Dy': 11250.0,
'GRIB_LaO': 90.0}
Interpolation to points¶
The method location()
creates
a dataset with all data variables interpolated to an arbitrary sequence of
locations within the original grid area (i.e. no extrapolation). Available
interpolation type can be nearest neighbour, bilinear and bicubic.
To specify point locations, use Point
. The constructor
accepts longitudes, latitudes and, optionally, coordinate labels.
# Coordinates from https://www.aviationweather.gov/docs/metar/stations.txt
sites = ["PAFA", "PAJN", "PANC"]
lons = [360 - (147 + 52/60), 360 - (134 + 33/60), 360 - (150 + 1/60)]
lats = [64 + 48/60, 58 + 21/60, 61 + 10/60]
locs = pywgrib2.Point(lons, lats, ('stid', sites, {'long_name': 'site identifier'}))
# Budget interpolation to points is not supported
iptype = {'3h_pcp': 'neighbour',
'3h_conv_pcp': 'neighbour',
'ceil': 'neighbour',
'default': 'bilinear',
}
ds_pts = ds.wgrib2.location(locs, iptype=iptype)
ds_pts.coords
Coordinates:
points int64 0
longitude (stid) float64 212.1 225.4 210.0
latitude (stid) float64 64.8 58.35 61.17
* stid (stid) <U4 'PAFA' 'PAJN' 'PANC'
* isobaric1 (isobaric1) int64<PHONE_NUMBER>0 95000 92500 ... 10000 7500 5000
reftime datetime64[ns] 2020-09-07
time1 timedelta64[ns] 06:00:00


---
sort_order: 172
tei_id: rdx_b5j2m.p.idm190656
annotation_count: 0
images:
small-thumbnail: http://readux.library.emory.edu/books/emory:b5j2m/pages/emory:p7972/mini-thumbnail/
json: http://readux.library.emory.edu/books/emory:b5j2m/pages/emory:p7972/info/
full: http://readux.library.emory.edu/books/emory:b5j2m/pages/emory:p7972/fs/
page: http://readux.library.emory.edu/books/emory:b5j2m/pages/emory:p7972/single-page/
thumbnail: http://readux.library.emory.edu/books/emory:b5j2m/pages/emory:p7972/thumbnail/
title: Page 172
number: 172
---
{% raw %}168 MRS. H. BEECHER STOWE's " UNCLE TOM."{% endraw %}
{% raw %}year passed away, and again I silenced the question¬{% endraw %}
{% raw %}ings and murmurings; for I still had confidence in{% endraw %}
{% raw %}his integrity of purpose. The third year passed, and{% endraw %}
{% raw %}then the coloured people began to tell me " I was in{% endraw %}
{% raw %}league with him, and that in some way he and I{% endraw %}
{% raw %}were gaining pecuniary advantages from the cultiva¬{% endraw %}
{% raw %}tion of that splendid tract of three hundred acres of{% endraw %}
{% raw %}land on the Sydenham River."{% endraw %}
{% raw %}By-and-by his finances became involved, and he{% endraw %}
{% raw %}borrowed of me several hundred dollars to meet his{% endraw %}
{% raw %}bills, and the fourth year passed ; still there was no{% endraw %}
{% raw %}school. He supported his family and his brother-in-{% endraw %}
{% raw %}law's family from the farm that belonged to our{% endraw %}
{% raw %}coloured people. True, the family of his brother-in-{% endraw %}
{% raw %}law, from their straitened circumstances, frequently{% endraw %}
{% raw %}came to my house for food, and my wife gave them{% endraw %}
{% raw %}the best we had. The fifth, sixth, seventh, eighth,{% endraw %}
{% raw %}and ninth year passed, and we had no school, and not{% endraw %}
{% raw %}an individual could make any change. He had no{% endraw %}
{% raw %}title to the land, so he had no power to sell this, and{% endraw %}
{% raw %}it was a most fortunate thing. I had repeatedly said{% endraw %}
{% raw %}to him, " The people are growling." He replied,{% endraw %}
{% raw %}" Let them growl." He invariably refused to dis¬{% endraw %}
{% raw %}cuss the question. At length, when nine years had{% endraw %}
{% raw %}passed, I began to doubt the man's intentions, and I{% endraw %}
{% raw %}thought I would have a serious conversation with{% endraw %}
{% raw %}him on the subject, and ascertain what he proposed{% endraw %}
{% raw %}doing. I said to him as politely as I could, " The{% endraw %}
{% raw %}people about here are beginning to talk very hard{% endraw %}
{% raw %}about you and myself, and I do not want to let them{% endraw %}
{% raw %}have any cause to think ill of us. If you will be so{% endraw %}
{% raw %}kind as to give me some intimation when you propose{% endraw %}


Central Logging
Server
Pick a server. I used pi-12-pp which is the first control node also.
On Logging Server
Create a place to hold all the logs.
sudo mkdir /var/log/central
sudo chown syslog:adm /var/log/central
Rsyslog will use TCP/UDP port 514, but you need to enable it. Edit /etc/rsyslog.conf, and make sure these lines look like this (by uncommenting them):
sudo nano /etc/rsyslog.conf
# provides UDP syslog reception
module(load="imudp")
input(type="imudp" port="514")
# provides TCP syslog reception
module(load="imtcp")
input(type="imtcp" port="514")
Next create config to tell rsyslog to put all logs in previously created folder, create /etc/rsyslog.d/45-central.conf
sudo nano /etc/rsyslog.d/45-central.conf
$template RemoteLogs,"/var/log/central/%HOSTNAME%.log"
*.* ?RemoteLogs
This will put all logs under /var/log/central/
Last thing, and this is kind of optional, we need to tell logrotate about this, and have it rotate the logs, so you don't end up with 100+MB text files.
Create file /etc/logrotate.d/central
/var/log/central/*.log
{
rotate 4
weekly
missingok
notifempty
compress
delaycompress
sharedscripts
postrotate
invoke-rc.d rsyslog rotate >/dev/null 2>&1 || true
endscript
}
rotate - How many rotated copies to keep before removing the oldest one.
weekly - Rotate log every 7 days.
missingok - If the log file is missing, go on to the next one without issuing an error message.
notifempty - Do not rotate the log if it is empty.
compress - Gzip the logs.
delaycompress - Postpone compression of the previous log file to the next rotation cycle.
sharedscripts - Because we are going to use wildcard, we need this argument, telling logrotate this setting is for multiple logs.
postrotate - What to do after rotation is finished, in this case invoke rsyslog rotate.
Some more info about options: https://linux.die.net/man/8/logrotate
Restart rsyslog
sudo systemctl restart rsyslog
That’s it for a server, no need to restart logrotate; that will be run via cron.
lnav
Just a nifty little program to watch your logs in real time, with filters and so on.
sudo apt install lnav
lnav /var/log/central/*.log


§660-25 Notice to other parties, when. If the person is detained on any process under which any other person has an interest in the person's detention, and the other person or the other person's attorney is within the State and can be notified without unreasonable delay, the person detained shall not be discharged until the other person or the other person's attorney has had an opportunity to be heard. [L 1870, c 32, §18; RL 1925, §2748; RL 1935, §4333; RL 1945, §10374; RL 1955, §239-25; HRS §660-25; am L 1972, c 90, §5(p); am L 2016, c 55, §40]
Cross References
Notice of parole or release, see §706-670.5.
Victim or witness rights, see chapter 801D.


| Home | Tutorials | The List Class | The Collection Class |
Reminder! To run these examples, you should first start a new session then load the sample database using:"/localvision/samples/general/sample.load" asFileContents evaluate ;Any other files referenced can be read from the /localvision/samples/general/ directory.Note: The sample.load file runs by default on a Unix environment. If you are using a Windows NT platform, this location may be prefixed by a drive and optional path (e.g. d:/visiondb/localvision/samples/general/sample.load). Check with your Vision Administrator for further details.
Vision allows you to store one or more objects in a list. To create a list, just separate the objects you wish to include in the list with commas. For example, assume you wish to create a list containing the companies GM, IBM, and Exxon and name this list testList. Type and execute the following:
!testList <- Named Company GM, Named Company IBM, Named Company XONYou should see:
List of 3Vision has executed your request and created a variable called testList. The output aList informs you that you have created a list of elements. If you wish to suppress the printing of aList, simply type ; at the end of the previous expression. Notice that the expression Named Company is repeated for each element in the list. The send: message can be used to streamline this operation. Type the following:
!testList <- Named Company send: [ GM, IBM, XON ]The two previous examples produce identical results.
The count message can be sent to a list of elements to return the number of elements in the list. For example, the expression:
testList countreturns the number 3, the total number of companies in testList.
To access the list of all instances in the class Company, execute the expression:
!fullList <- Company masterList ;Vision has executed your request and created a variable called fullList. The expression:
fullList countreturns the number 38, the total number of companies in fullList.
The asList message can be used to produce a 1 element list from a single object. For example:
!gmAsList <- Named Company GM asList ;produces a list object that contains 1 object, the company GM. You can append additional objects to gmAsList and use all the other List messages with this list.
Individual objects in a List can be accessed directly using the at: message. For example, the expression:
testList at: 2returns the second element of this list. In this case, the Company object IBM is returned. The expression:
(testList at: 2) = Named Company IBMreturns the value TRUE.
Now that you know how many companies are in testList, you may wish to analyze and display information for each company in the list. The do: message is used for this purpose. You used this message in a previous section to display multiple pieces of information for a single company.
The syntax for the do: message is:
list do: [ operation 1 ; operation 2 ; operation 3 ; . . . operation n ; ] ;where list is a list of elements (e.g., testList) and each operation represents an action you want executed for each element in the list. As usual, each separate operation is followed by the ; character.
The expression:
testList do: [ ticker print; ] ;produces the output:
GMIBMXONThis program prints the ticker for each company in testList. However, the output in this example is almost unreadable. That is because you did not tell Vision to perform a carriage return after printing each ticker. Instead of using the print message, use printNL as shown below:
testList do: [ ticker printNL; ] ;The Output Window should display:
GM IBM XONThis program prints a ticker for each company in testList, followed by a carriage return.
The message do: operates like a loop that says print the ticker for company 1 in testList followed by a carriage return, print the ticker for company 2 in testList followed by a carriage return, and so on. If you wished to perform this same operation for a list containing 10,000 companies, only the list name would need to be changed. For example, you could use fullList to display the ticker for each company instance:
fullList do: [ ticker printNL; ] ;Suppose you wish to print the names of the companies in testList. The expression:
testList do: [ name printNL ] ;produces:
General Motors Corp IBM Corp Exxon CorpIn addition to name, print the sales for each company in testList. The expression:
testList do: [ name print; sales printNL; ] ;produces:
General Motors Corp 101781.00 IBM Corp 54217.02 Exxon Corp 76416.00To get the sales column to line up neatly, specify a column width for the name using the print: message as shown below:
testList do: [name print: 35; sales printNL; ] ;You should see:
General Motors Corp 101781.00 IBM Corp 54217.02 Exxon Corp 76416.00The message print: 35 reserves 35 spaces for each company's name and inserts spaces for names that have fewer characters.
The do: message can be used with calculations as well. Suppose you wish to calculate the price-earnings ratio for each company in testList. The expression:
testList do:[ name print: 35; sales print: 10 ; price / earningsPerShare printNL: 8 ; ] ;produces the results:
General Motors Corp 101781.00 6.39 IBM Corp 54217.02 9.26 Exxon Corp 76416.00 8.62In this case, the do: message executes three operations for each element in the list, printing the name, the sales value, and the price-earnings ratio followed by a carriage return. The sales values is printed in 10 character positions and the price-earnings ratio is printed in 8 positions. Change testList to fullList to execute this report for all the companies.
It is often useful to restrict a list to objects that meet certain criteria. For example, you may wish to find the companies in fullList whose sales were greater than 15,000 and produce the previous report for these companies only. The expression:
fullList select: [ sales > 15000 ] . do: [ name print: 35 ; sales print: 10 ; price / earningsPerShare printNL: 8 ; ] ;produces:
Aetna Life & Cas 22114.11 5.46 American Tel & Tel 51209.02 23.20 Amoco Corp 20174.00 19.91 Atlantic Richfield 16282.00 18.15 Boeing Co 15355.00 26.63 ...This expression selects companies in fullList whose sales were greater than 15,000 and displays each company's name, sales, and price-earnings ratio for the companies that passed the criteria.
The select: message returns a list of those elements in the original list that meet the criteria specified. Pictorially the select: message works as follows:
The resultant list is a new list object that contains a subset of the objects in the original list. The resultant list can be empty (i.e., contain no objects) but will never have more elements than the original list. When you send the do: message to the resultant list, the report is only produced for those companies in this list. This same task could have been accomplished by creating a new variable that represents the result of screening for the specified criteria and then producing the report for this list as shown below:
!selectList <- fullList select: [ sales > 15000 ] ; selectList do: [ name print: 35 ; sales print: 10 ; price/earningsPerShare printNL: 8 ; ];This program produces results that are identical to the previous example.
If you wish to find the companies that had sales greater than 15,000 and a price-earnings ratio of less than 10, type the expression:
fullList select: [ sales > 15000 && (price / earningsPerShare) < 10 ] . do: [ name print:35; sales print: 10 ; price / earningsPerShare printNL: 8 ; ] ;You should see
Aetna Life & Cas 22114.11 5.46 CIGNA Corp 16909.30 6.90 Chrysler Corp 26276.51 3.92 Citicorp 27988.01 3.67 Ford Motor Company 71643.38 4.36 General Motors Corp 101781.00 6.39 IBM Corp 54217.02 9.26 Travelers Corp 17459.10 5.49The message && is the relational operator for and. It is used to create selection criteria where several criteria must all be TRUE. The message | | is the relational operator for or and is used to specify criteria where either or both criteria are TRUE. For example, if you wish to find the companies whose sales are greater than 15,000 or that have a price-earnings ratio of less than 15, execute:
fullList select: [ sales > 15000 || (price / earningsPerShare) < 10 ] . do: [ name print: 35 ; sales print: 10 ; price/ earningsPerShare printNL: 8 ; ];You should see:
Aetna Life & Cas 22114.11 5.46 American Tel & Tel 51209.02 23.20 Amoco Corp 20174.00 19.91 Atlantic Richfield 16282.00 18.15 Boeing Co 15355.00 26.63 ...Notice that calculations (e.g., price / earningsPerShare) can be performed within selection brackets. The selection criteria is really just a Vision program. Within the square brackets, you can define temporary variables, perform conditional tests, and do complex calculations to specify your criteria.
It is often useful to display your information in sorted order. The sortDown: and sortUp: messages enable you to do this. For example, after you performed your screen on fullList, you may wish to display the results from highest to lowest sales. For example, the expression:
fullList select: [ sales > 15000 && (price / earningsPerShare) < 10 ] . sortDown: [ sales ] . do: [ name print: 35 ; sales print: 10 ; price / earningsPerShare printNL: 8 ; ] ;produces the output:
General Motors Corp 101781.00 6.39 Ford Motor Company 71643.38 4.36 IBM Corp 54217.02 9.26 Citicorp 27988.01 3.67 ...As with other list messages, you are not limited in the complexity of the calculation to be sorted on. For example you may sort on the price-earnings ratio by executing the following:
fullList select: [ sales > 15000 && (price / earningsPerShare) < 10 ] . sortUp: [ price / earningsPerShare ] . do: [ name print: 35 ; sales print: 10 ; price / earningsPerShare printNL: 8 ; ] ;producing the results:
Citicorp 27988.01 3.67 Chrysler Corp 26276.51 3.92 Ford Motor Company 71643.38 4.36 Aetna Life & Cas 22114.11 5.46 ...In this case, the sortUp: message was used to sort the values from lowest to highest price-earnings ratio. You can perform multiple sorts using the sortUpBy: then: message and supplying two criteria. For example, to sort by the integer portion of the price-earnings ratio then by name, use:
fullList select: [ sales > 15000 && (price / earningsPerShare) < 10 ] . sortUpBy: [ (price / earningsPerShare) asInteger ] then: [ name ] . do: [ name print: 35 ; sales print: 10 ; price / earningsPerShare printNL:8 ; ] ;
You should see:
Chrysler Corp 26276.51 3.92 Citicorp 27988.01 3.67 Ford Motor Company 71643.38 4.36 Aetna Life & Cas 22114.11 5.46 ...Notice that Chrysler now appears before Citicorp. Since the integer value of the ratio is 3 in both cases, the name sort is used as a secondary sort.
Additional variations of the Sort:messsages are available.
The last example used the calculation price / earningsPerShare three times (selecting, sorting, and doing) thus creating two inefficiencies. First, it is tedious to type in the same calculation three times, particularly when calculations use many variables. In addition, by writing the calculation three times, you are asking Vision to retrieve the same information for the same companies three times. As usual, Vision provides a more efficient way to accomplish this.
The message extendBy: lets you calculate variables once for each element in the list and then lets you reuse this information. For example, the previous example can be more effectively written as follows:
fullList extendBy: [ !pe <- price / earningsPerShare; ] . select: [ sales > 15000 && pe < 10 ] . sortUpBy: [ pe ] then: [ name ] . do: [ name print: 35 ; sales print: 10 ; pe printNL: 8 ; ] ;This program produces the same output as the prior example. Instead of calculating price / earningsPerShare three times, the extendBy: message allows you to create a variable that stores the result of this calculation once.
All objects in the list respond to the pe message just like any other message. All objects in the list continue to respond to the messages already defined.
Pictorially the extendBy: message works as follows:
Within the square brackets, you can define as many variables as you would like. Each variable should be introduced with the symbol ! followed by a variable name. Each variable that you define can be thought of as a new column for the list. For example:
fullList extendBy: [ !pe <- price / earningsPerShare; !margin <- netIncome / sales; ] . select: [ sales > 15000 && pe < 10 ] . sortUp: [ pe ] . do:[ name print: 35 ; margin print ; sales print: 10 ; pe printNL: 8 ; ] ;produces:
Citicorp 0.04 27988.01 3.67 Chrysler Corp 0.05 26276.51 3.92 Ford Motor Company 0.06 71643.38 4.36 Aetna Life & Cas 0.04 22114.11 5.46 Travelers Corp 0.02 17459.10 5.49 General Motors Corp 0.03 101781.00 6.39 CIGNA Corp 0.04 16909.30 6.90 IBM Corp 0.10 54217.02 9.26The new variable definitions can be as simple or complex as needed. For example, you could create an additional variable that contains an * if margin is more than .9 or sales is less than 20,000 using:
fullList extendBy: [ !pe <- price / earningsPerShare; !margin <- netIncome / sales; !flag <- " " ; margin > .9 || sales < 20000 ifTrue:[ :flag <- "*"; ] ; ] . select: [ sales > 15000 && pe < 10 ] . sortUp: [ pe ] . do: [ flag print: 2 ; name print: 35 ; margin print ; sales print: 10 ; pe printNL: 8 ; ] ;producing the output:
Citicorp 0.04 27988.01 3.67 Chrysler Corp 0.05 26276.51 3.92 Ford Motor Company 0.06 71643.38 4.36 Aetna Life Cas 0.04 22114.11 5.46 * Travelers Corp 0.02 17459.10 5.49 General Motors Corp 0.03 101781.00 6.39 * CIGNA Corp 0.04 16909.30 6.90 IBM Corp 0.10 54217.02 9.26
You may wish to determine the rank of each company in a list based on one of its data values. In fullList, for example, the company with the highest sales would receive a rank of 1 and the one with the lowest sales would receive a rank of 38. Vision provides two messages, rankUp: and rankDown: for this purpose. The rankUp:message assigns the value 1 to the list element with the lowest value for the supplied criteria. The rankDown: message assigns the value 1 to the list element with the highest value for the supplied criteria.
When you send one of these messages to a list, Vision returns an extended variable for the list named rank. For example, if you wished to rank the companies selected in the previous examples from highest to lowest sales and sort the companies by pe, you could execute:
fullList extendBy: [ !pe <- price / earningsPerShare; !margin <- netIncome / sales; ] . select: [ sales > 15000 && pe < 10 ] . rankDown: [ sales ] . sortUp: [ pe ] . do: [ name print: 30 ; margin print ; sales print: 10 ; rank print ; pe printNL: 8 ; ] ;producing the output:
Citicorp 0.04 27988.01 4 3.67 Chrysler Corp 0.05 26276.51 5 3.92 Ford Motor Company 0.06 71643.38 2 4.36 Aetna Life & Cas 0.04 22114.11 6 5.46 Travelers Corp 0.02 17459.10 7 5.49 General Motors Corp 0.03 101781.00 1 6.39 CIGNA Corp 0.04 16909.30 8 6.90 IBM Corp 0.10 54217.02 3 9.26The displayed rank indicates the company's position in the list by sales. Citicorp, with a sales rank of 4, is displayed first because the report is sorted by pe and Citicorp has the lowest pe value. If you were to rank and sort the list by the same value, the companies will display in rank order. For example, to rank and sort the list by pe, type the following:
fullList extendBy: [ !pe <- price / earningsPerShare ; !margin <- netIncome / sales ; ] . select: [ sales > 15000 && pe < 10 ] . rankUp: [ pe ] . sortUp: [ pe ] . do: [ name print: 30 ; margin print ; sales print: 10 ; rank print ; pe printNL: 8 ; ] ;producing the output:
Citicorp 0.04 27988.01 1 3.67 Chrysler Corp 0.05 26276.51 2 3.92 Ford Motor Company 0.06 71643.38 3 4.36 Aetna Life & Cas 0.04 22114.11 4 5.46 Travelers Corp 0.02 17459.10 5 5.49 General Motors Corp 0.03 101781.00 6 6.39 CIGNA Corp 0.04 16909.30 7 6.90 IBM Corp 0.10 54217.02 8 9.26Notice that the ranks are in ascending order in this case.
In the last few examples, you have performed the same extendBy: and select: operations repeatedly. You may wish to create a new list that represents the original list containing only those companies meeting your criteria and providing the two pre-calculations. To do this, type:
!subset <- fullList extendBy: [ !pe <- price / earningsPerShare; !margin <- netIncome / sales; ]. select: [ sales > 15000 && pe < 10] ;The variable subset can now be used directly. For example, to generate the last report using this list type:
subset rankUp: [ pe ] . sortUp: [ pe ] . do: [ name print: 30 ; margin print; sales print: 10 ; rank print; pe printNL: 8 ; ] ;The output should be identical to the previous report. Notice that there was no need to do the extend: or select: operations this time.
The decileUp: and decileDown: messages have been implemented to assign a value from 1 to 10 to each element in the list based on the criteria supplied. The decileUp: message assigns the value 1 to the first 10% of the list elements with the lowest values, the value 2 to the next 10%, and so on with the value 10 assigned to the list elements in the top 10%. The decileDown: message assigns the value 1 to the first 10% of the list elements with the highest values and the value 10 to the list elements in the bottom 10%. When you send one of these messages to a list, Vision returns an extended variable for the list named decile. For example:
fullList decileDown: [ sales ] . do: [ name print: 30 ; sales print: 10 ; decile printNL ; ] ;produces the output:
Aetna Life & Cas 22114.11 4 American Tel & Tel 51209.02 2 Amoco Corp 20174.00 4 Atlantic Richfield 16282.00 6 ...Each company is assigned a decile value from 1 to 10 based on where its sales value falls compared to the other companies in the list. The companies with the largest sales all have the decile value 1. The companies with the smallest sales all have the decile value 10. Sorting the list by sales may make this clearer:
fullList decileDown: [ sales ] . sortDown: [ sales ] . do: [ name print: 30 ; sales print: 10 ; decile printNL ; ] ;You should see:
General Motors Corp 101781.00 1 Exxon Corp 76416.00 1 Ford Motor Company 71643.38 1 IBM Corp 54217.02 1 Mobil Corporation 51223.02 2 American Tel & Tel 51209.02 2 Sears Roebuck & Co 48439.61 2 General Electric Co 39315.01 2 DuPont EI de Nemours 30468.01 3 . . .The quintileUp: and quintileDown: messages are identical to the decile messages except they assign a value from 1 to 5, returned in a variable named quintile. For example, you could assign a sales quintile and an earningsPerShare decile value using the following:
fullList quintileDown: [ sales ] . decileUp: [ earningsPerShare ] . do: [ name print: 30 ; sales print: 10 ; quintile print ; earningsPerShare print ; decile printNL ; ] ;producing the output:
Aetna Life & Cas 22114.11 2 7.48 9 American Tel & Tel 51209.02 1 1.88 2 Amoco Corp 20174.00 2 2.65 4 Atlantic Richfield 16282.00 3 6.68 8 BellSouth Corp 12269.10 4 3.46 6 Boeing Co 15355.00 3 1.38 2 ...
The groupedBy: message provides you with a powerful tool for aggregation, enabling you to simultaneously analyze information at a detailed and aggregate level. The groupedBy: message is used to organize your original list into a list of sublists or groups based on criteria that you specify. You can then perform summary analysis on each group as well as analyze the individual elements in each group.
The groupedBy: message is often used to group information by industry, analyst, rating, or any other criteria that allows you to classify similar information.
To group the list subset by sector, and display each sector's name, type the following expression:
subset groupedBy: [ industry sector ] . do: [ name printNL; ] ;You should see:
Durables Finance TechnologyBy asking Vision to group subset by sector, Vision returns a list of the sectors that exist in subset. When you send the do: message to this list and ask for the name of each element to be printed, the sector names are displayed.
Your original list of companies is not lost. Each element in the list formed by the groupedBy: message responds to the message groupList. This message returns the list of companies from the original list that are associated with the specific group. To determine the number of companies in each sector, type the following:
subset groupedBy: [ industry sector ] . do: [ name print: 35 ; groupList count printNL; ] ;producing the output:
Durables 3 Finance 4 Technology 1To display the companies in each sector, and the sales, pe and margin for each company, type the following:
subset groupedBy: [ industry sector ] . do: [ name printNL; # print sector name groupList do: [ # for each company in sector " " print:5; # indent 5 spaces name print: 30 ; # print company data margin print ; sales print: 10 ; pe printNL; ] ; ];You should see:
Durables Chrysler Corp 0.05 26276.51 3.92 Ford Motor Company 0.06 71643.38 4.36 General Motors Corp 0.03 101781.00 6.39 Finance Aetna Life & Cas 0.04 22114.11 5.46 CIGNA Corp 0.04 16909.30 6.90 Citicorp 0.04 27988.01 3.67 Travelers Corp 0.02 17459.10 5.49 Technology IBM Corp 0.10 54217.02 9.26Pictorially the groupedBy: message works as follows:
Grouping introduces a concept known as nested lists. The outer list represents a list of sectors. Each element in this outer list in turn responds to the message groupList which returns the set of elements from the original list that are in the current group. Since this subset is itself a list, you can perform any list operations on it, including count, do:, and select:. For example, to sort the companies in each group by sales, use the following:
subset groupedBy: [ industry sector ] . do: [ name printNL ; # print sector name groupList sortDown: [ sales ] . # sort companies in sector do: [ # sort each company in sector do: [ " " print: 5 ; # indent 5 spaces name print: 30 ; # print company data margin print ; sales print: 10 ; pe printNL ; ] ; ] ;You should see:
Durables General Motors Corp 0.03 101781.00 6.39 Ford Motor Company 0.06 71643.38 4.36 Chrysler Corp 0.05 26276.51 3.92 Finance Citicorp 0.04 27988.01 3.67 Aetna Life & Cas 0.04 22114.11 5.46 Travelers Corp 0.02 17459.10 5.49 CIGNA Corp 0.04 16909.30 6.90 Technology IBM Corp 0.10 54217.02 9.26You can sort each of the group levels independently. For example, you could sort the sector groups by number of companies in the group using the following:
subset groupedBy: [ industry sector ] . sortUp: [ groupList count ] . # sort sectors by number in group do: [ name printNL ; # print sector name groupList sortDown: [ sales ] . # sort companies in sector do: [ # for each company in sector do: [ " " print: 5 ; # indent 5 spaces name print: 30 ; # print company data margin print ; sales print: 10 ; pe printNL; ] ; ] ;You should see:
Technology IBM Corp 0.10 54217.02 9.26 Durables General Motors Corp 0.03 101781.00 6.39 Ford Motor Company 0.06 71643.38 4.36 Chrysler Corp 0.05 26276.51 3.92 Finance Citicorp 0.04 27988.01 3.67 Aetna Life & Cas 0.04 22114.11 5.46 Travelers Corp 0.02 17459.10 5.49 CIGNA Corp 0.04 16909.30 6.90Since the groupList is a list, it can be grouped further, as shown below:
subset groupedBy: [ industry sector ] . # group by sector do: [ "SECTOR: " print; name printNL; # print sector's name groupList groupedBy: [ industry ] . # group companies in sector do: [ # by industry " INDUSTRY: " print; name printNL; # print industry's name groupList # for each company do: [ # in industry do: " " print: 8 ; # indent 8 spaces name print: 30 ; # print company data sales print:10 ; price print:10 ; earningsPerShare print: 10 ; newLine print ; ] ; # end of companies in ind. ] ; # end of industries in sector newLine print; # skip line between sectors ] ; # end of sectorsYou should see:
SECTOR: Durables INDUSTRY: Automotive Chrysler Corp 26276.51 23.13 5.90 Ford Motor Company 71643.38 39.50 9.05 General Motors Corp 101781.00 32.13 5.03 SECTOR: Finance INDUSTRY: Banks Citicorp 27988.01 15.63 4.26 INDUSTRY: Insurance Aetna Life & Cas 22114.11 40.88 7.48 CIGNA Corp 16909.30 50.00 7.25 Travelers Corp 17459.10 22.50 4.10 SECTOR: Technology INDUSTRY: Computers and Services IBM Corp 54217.02 80.75 8.72 ...This report organizes the list subset into sectors. Within each sector the industries are separated, and then the companies are listed under their corresponding industry. This example uses the groupedBy: message twice; once to group the original list into sectors; the second time to group the companies in a given sector into industries. You can change the initial list from subset to fullList, to display this report for all companies.
Vision offers various messages for calculating summary statistics about a list. For example, if you wish to calculate the average sales for the companies in fullList execute:
fullList average: [ sales ]You should see:
25701.95To determine the total sales in fullList execute:
fullList total: [ sales ]producing the output:
976674.02Other statistical messages include: average:, max:, median:, min:, mode:, stdDev:, and total:.
Many of these messages, such as median: were written in Vision and can be modified or expanded as needed. The brackets can contain a simple message, a calculation, or a complex program.
To save the total, average, minimum and maximum sales for the companies in fullList in the variables fullTot, fullAvg, fullMin, and fullMax respectively, execute:
!tot <- fullList total: [ sales ]; !avg <- fullList average: [ sales ]; !min <- fullList min: [ sales ]; !max <- fullList max: [ sales ];To print the results for each variable with a description execute:
"TOTAL SALES" print: 35 ; tot printNL ; "AVERAGE SALES" print: 35 ; avg printNL ; "MIN SALES" print: 35 ; min printNL ; "MAX SALES" print: 35 ; max printNL ;producing the output:
TOTAL SALES 976674.02 AVERAGE SALES 25701.95 MIN SALES 8090.00 MAX SALES 101781.00The following program adds subtotals to the sector report created earlier:
subset groupedBy: [ industry sector ] . do: [ printNL ; # print sector name groupList do: [ # for each company in sector do: [ " " print: 5 ; # indent 5 spaces name print: 30 ; # print company data sales printNL; ] ; "SUB TOTALS: " print: 35 ; groupList total: [ sales ] . printNL ; newLine print ; ] ;You should see:
Durables Chrysler Corp 26276.51 Ford Motor Company 71643.38 General Motors Corp 101781.00 SUB TOTALS: 199700.89 Finance Aetna Life & Cas 22114.11 CIGNA Corp 16909.30 Citicorp 27988.01 Travelers Corp 17459.10 SUB TOTALS: 84470.52 . . .To display subtotals for the industry-sector report, use:
fullList groupedBy: [ industry sector ] . do: [ "Sector: " print ; name printNL ; groupList groupedBy: [ industry ] . do: [" Industry: " print ; name printNL ; groupList do:[ " " print: 8 ; name print: 30 ; sales print: 10 ; price print: 10 ; earningsPerShare print: 10 ; newLine print ; ]; #-- Industry Sub Totals "Industry Totals: " print: 38 ; groupList total: [ sales ] . print: 10 ; " " print: 10 ; groupList average: [ earningsPerShare ] . print: 10 ; newLine print ; newLine print ; ]; #-- Sector Sub Totals "Sector Totals: " print: 38 ; groupList total: [ sales ] . print: 10 ; " " print: 10 ; groupList average: [ earningsPerShare ] . print: 10 ; newLine print ; newLine print ; ] ; # end of sectorsproducing the output:
Sector: Non-durables Industry: Food, Beverage, Tobacco Pepsico Inc 11485.20 37.88 0.77 Philip Morris Cos 22279.00 84.75 1.94 Industry Totals: 33764.20 1.35 Industry: Household Products Eastman Kodak Co 13305.00 44.50 3.52 Procter & Gamble Co 17000.00 49.38 0.47 Industy Totals: 30305.00 2.00 Sector Totals: 64069.20 1.68 Sector: Durables Industry: Automotive Chrysler Corp 26276.51 23.13 5.90 Ford Motor Company 71643.38 39.50 9.05 General Motors Corp 101781.00 32.13 5.03 Industry Totals: 19700.89 6.66 Sector Totals: 199700.89 6.66 ...
Many applications require merging several lists together. Vision offers several messages to support these operations. Start by creating two lists: techList which contains the companies IBM, DEC, and HWP and highSalesList which includes companies with sales over 15,000.
!techList <- Named Company send: [ IBM, DEC, HWP ] ; !highSalesList <- fullList select: [ sales > 15000 ] ;First, determine the number of companies in each list:
techList countYou should see:
3Now type:
highSalesList countYou should see:
22Suppose you wish to create a new list which includes all of the companies in highSalesList and techList. The append: message can be used for this purpose. To define a new list called combinedList with all of the companies in both lists execute the following:
!combinedList <- highSalesList append: techList;Now count the number of companies in combinedList using:
combinedList countproducing the output:
25To print the names of the companies in combinedList type the following:
combinedList do: [ name printNL ] ;You should see:
Aetna Life & Cas American Tel & Tel Amoco Corp Atlantic Richfield Boeing Co CIGNA Corp Chevron Corp Chrysler Corp Citicorp DuPont EI de Nemours Exxon Corp Ford Motor Company GTE Corp General Electric Co General Motors Corp IBM Corp K Mart Corp Mobil Corporation Philip Morris Cos Procter & Gamble Co Sears Roebuck & Co Travelers Corp IBM Corp Digital Equipment Corp Hewlett-Packard CoNotice that IBM appears twice. The append: message does not remove duplicate companies. To eliminate the duplication, use the union: message. Union finds elements that are in either or both lists specified. Change the previous example to use union: instead of append: :
!combinedList <- highSalesList union: techList; combinedList do: [ name printNL; ];You should see the following:
Aetna Life & Cas American Tel & Tel Amoco Corp Atlantic Richfield Boeing Co CIGNA Corp Chevron Corp Chrysler Corp Citicorp Digital Equipment Corp DuPont EI de Nemours Exxon Corp Ford Motor Company GTE Corp General Electric Co General Motors Corp Hewlett-Packard Co IBM Corp K Mart Corp Mobil Corporation Philip Morris Cos Procter & Gamble Co Sears Roebuck & Co Travelers CorpNotice that this time, IBM appears only once.
Suppose you wish to create a list of all companies excluding the companies in techList. Use the exclude: message as shown below:
!fullNoTechList <- fullList exclude: techList; fullNoTechList countproducing the output:
35Notice that now there are only 35 companies. If you wish to know which ones, you can execute the following:
fullNoTechList do: [ name printNL; ];producing the output:
Aetna Life & Cas American Tel & Tel Amoco Corp Atlantic Richfield BellSouth Corp ...To determine which companies are in both techList and highSalesList, execute the following:
techList intersect: highSalesList . do: [ name printNL ] ;You should see:
IBM CorpThe numberElements message is used to extend the list by the variable position which represents the element's position in the list. For example:
subset numberElements do: [ name print: 35 ; position printNL ; ] ;produces the output:
Aetna Life & Cas 1 CIGNA Corp 2 Chrysler Corp 3 Citicorp 4 Ford Motor Company 5 General Motors Corp 6 IBM Corp 7 Travelers Corp 8
| Vision Basics | Creating A Demo Database | Single Object Access | Using Dates and TimeSeries |
| Copyright © 1999 Innovative Systems Techniques, Inc. | Updated January 25, 1999 |


Red Hat
JBoss BRMS & BPM Suite
Online Workshops
Part I - JBoss BRMS & BPM Suite
Part II - JBoss BRMS
Online Workshop
This workshop will teach you how to build an online web shop called the
Cool Store by designing various rules, events, and ruleflows.
Part III - JBoss BPM Suite
Online Workshop
This workshop will teach you how to build a business process for a company that wants
to automate its human resource (HR) employee awards program.
Part IV - JBoss BPM Suite
- optional bpmPaaS workshop, use one of the instances below, start by jumping directly to
lab 12:
- bpmpaas1 (u:erics, p:bpmsuite)
- bpmpaas2 (u:erics, p:bpmsuite)
- bpmpaas3 (u:erics, p:bpmsuite)
- bpmpaas4 (u:erics, p:bpmsuite)
- bpmpaas5 (u:erics, p:bpmsuite)
- bpmpaas6 (u:erics, p:bpmsuite)
- bpmpaas7 (u:erics, p:bpmsuite)
- bpmpaas8 (u:erics, p:bpmsuite)
- bpmpaas9 (u:erics, p:bpmsuite)
- bpmpaas10 (u:erics, p:bpmsuite)


Rudimentary JavaScript parser for SOAP messages transmitted in .NET Binary. Based on Microsoft Open Specifications Documentation documents: MC-NBFX (6.0), MC-NBFS (4.0).
Wrote this over 5 days in TypeScript around the New Year 2016 period; I was working with a project that ported an WCF consuming application that talked to a server configured to communicate SOAP messages only in NBFX binary format. I stopped because we decided it was probably better to just reconfigure the server to use text XML that could be fed into a browser's native DOM/XML parser.
Code's a bit crummy inside but it works surprisingly robustly with a couple hundred KB of raw data (though the unoptimised JS is slow with such large inputs...) I thought it might be of interest to someone in the same position as I was in porting applications using WCF in the NBFX format.
Notes:
Enter base64 encoded raw data: (Note large input may slow/crash browser)
Output: