Fork me on GitHub
#beginners
<
2020-03-08
>
johnwesonga04:03:51

I’m tinkering with Oz a Clojure viz library https://github.com/metasoarous/oz and just following the steps in the README, but when I try and render my first viz nothing loads, when I inspect the console in Chrome I see this: Error: Invalid field type "undefined". at qi (oz.js:28) at Ii (oz.js:28) at oz.js:28 at hp (oz.js:28) at new wp (oz.js:28) at jp (oz.js:28) at Object.e.compile (oz.js:28) at CB (oz.js:1205) at Object.<anonymous> (oz.js:1206) at Object.<anonymous> (oz.js:823) my code:

(ns learning-clojure.viz
  (:require [oz.core :as oz]))

(oz/start-server!)


(defn play-data [& names]
  (for [n names
        i (range 20)]
    {:time i :item n :quantity (+ (Math/pow (* i (count n)) 0.8) (rand-int (count n)))}))

(def line-plot
  {:data {:values (play-data "monkey" "slipper" "broom")}
   :encoding {:x {:field "time"}
              :y {:field "quantity"}
              :color {:field "item" :type "nominal"}}
   :mark "line"})

;; Render the plot
(oz/view! line-plot) 

johnwesonga04:03:25

Figured out the issue, the :field needs a :type value set otherwise it breaks

pez08:03:26

@glfinn83 Calva has a command for loading those tools into the REPL. Don't know if you knew.

glfinn8308:03:20

Awesome! Is it ctrl + shift c enter?

pez09:03:29

The command is named... lemme check ... Require REPL utilities, like (doc) etcetera, into Current Namespace, default keybinding is ctrl+shit+c ctrl+u. (It is mostly useful for the REPL window. In the editor most of that functionality is built into the UI.)

glfinn8309:03:47

Thanks good sir!

borkdude12:03:23

This might be useful to beginners: https://github.com/porkostomus/4bb It's 4clojure but as a clojure / babashka script, so you can run it locally.

alidcastano18:03:11

i have a keymap utility i’m rewriting in Clojurescript, wondering if there’s a better way to write this function:

function concatModifierKeyNames(_k: string, mods: ModifierMap) {
  let k = _k.slice()
  if (mods.alt) k = `Alt+${k}`
  if (mods.ctrl) k = `Ctrl+${k}`
  if (mods.meta) k = `Meta+${k}`
  if (mods.shift) k = `Shift+${k}`
  return k}
currently I have this:
(defn concat-modifier-keynames [k mods]
  (let [k (if (:alt mods) (str "Alt+" k) k)
        k (if (:ctrl mods) (str "Ctrl+" k) k)
        k (if (:meta mods) (str "Meta+" k) k)
        k (if (:shift mods) (str "Shift+" k) k)]
    k))
but i’m redeclaring/tossing the k variable around more than I’d like. is there a better way to conditionally concat strings like this?

ghadi18:03:50

@alidcastano do the modifiers have to appear in a certain order?

mark54018:03:46

@alidcastano One thing that may help is that str will ignore nil values, and when returns nil when the condition is false.

mark54018:03:21

(str (when (= 1 2) "not true") 
     (when (= 1 1) " is true") 
     (when true " always"))
=> " is true always"

codonnell18:03:39

I would probably use cond->>:

(defn concat-modifier-keynames [k {:keys [alt ctrl meta shift]}]
  (cond->> k
    alt (str "Alt+")
    ctrl (str "Ctrl+")
    meta (str "Meta+")
    shift (str "Shift+")))

alidcastano19:03:42

This is a great solution, thanks

slgeorge21:03:48

I'm struggling to understand how to iterate across a collection of maps. If I have a simple structure then I can use destructuring. So:

(def map2 {:name "Molly", :species "cat", :colour "grey", :age 9} )
(let [{:keys [age species]} map2] (print age species)) ;;=> 9 cat
But, if I have something more complex:
(def animals [{:name "Molly" :species "cat", :colour "grey", :age 9}
              {:name "Jack" :species "cat" :colour "ginger" :age 8}]
I can't figure out how to iterate across each map and pull out elements to use them. So far I can get it to use map to iterate across each individual map in turn. But, I can't get it to destructure the individual elements so I can use them. So far I've tried this, but it keeps saying "Unable to resolve symbol: age in this context"
(defn current_animals [animals]
    (map
        #(
            [{:keys [age species]} %]
        ) animals))
Can someone give me an idea what I'm doing wrong?

mark54021:03:56

Instead of using an anonymous function:

#(
            [{:keys [age species]} %]
        )
Use a regular fn:
(fn [{:keys [age species]}]  ...)
The parameters of a regular fn can use destructuring.

mark54021:03:41

Or you can use a let, which also allows destructuring on the left side of the binding.

slgeorge21:03:27

ah so that works! There must be something I don't understand about the anonymous function macro:

#( .... )

mark54021:03:58

It is just a short hand, and it is more limited in functionality.

mark54021:03:27

It is meant to be used only for simple, short functions.

slgeorge21:03:01

thanks @ - been trying to get that working for ages today 🙂

mark54021:03:32

you're welcome!

eagonmeng22:03:02

@ Think of the anonymous function as an extra pair of parens that calls what you have, meaning that #([...]) is actually (fn[] ([...])) , that is, you're calling the vector as a function. It's just shorthand and useful if you do want to make such a call (to say map or update or something), but remember that there's a pair of parentheses that calls the first thing in the anonymous form

slgeorge22:03:15

Ah thanks for that, now I understand why. Yeah, so:

(macroexpand-1 '#()) ;;=> (fn* [] ())

mark54022:03:15

(quote #(+ 1 %))
=> (fn* [p1__3179#] (+ 1 p1__3179#))
(quote #(+ %1 %2))
=> (fn* [p1__3184# p2__3185#] (+ p1__3184# p2__3185#))

mark54022:03:30

The expansion is done by the reader rather than it being a macro.

glfinn8321:03:17

In a book I'm reading it says that cons returns a 'logical' list, a sequence (not a list). Which exact implementation of ISeq is being returned?

mark54022:03:51

Try

(type (cons ...))
in the repl.

jason35822:03:02

you'll get different things, depending on what you're consing to

hindol.adhya03:03:06

Not OP, but learned something new today. I (wrongly) thought cons returns a sequence no matter what. Thanks!

mark54004:03:57

It does return a sequence no matter what, as defined by seq?, just different concrete types (which shouldn't matter).

(type (cons 1 nil))
  (type (cons 1 [1]))
  (seq? (cons 1 nil))
  (seq? (cons 1 [1]))

=> clojure.lang.PersistentList
=> clojure.lang.Cons
=> true
=> true